Redis Lua script detailed explanation of LUA script high-frequency interview questions

Get into the habit of writing together! This is the sixth day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

Redis launched the script function in 2.6, which can be written in Lua language and passed to Redis for execution.

Advantages of scripts:

  1. Reduce network overhead: The original 5 network requests can be completed with one request, and the original 5 request logic is sent to the redis server to complete. Reduced network round-trip latency, which is similar to pipes.
  2. Atomic operation: Redis will execute the entire script as a whole, without intervening other commands.
  3. Replacing the transaction function of Redis: The transaction function that comes with Redis is very tasteless, and the lua script of redis almost realizes the conventional transaction function. It is officially recommended that if you want to use the transaction function of redis, you can consider using lua instead.

Script usage instructions

Through the built-in lua interpreter, you can use EVALcommands to apply for Lua scripts. The command format is as follows:

# 脚本格式
EVAL script numkeys key [key ...] arg [arg ...]
# 示例
127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 k1 k2 a1 a2 
1) "k1"
2) "k2"
3) "a1"
4) "a2"
复制代码

Parameter Description:

The first script parameter is a Lua script, which will be run in the context of the redis server. This script does not (and should not) be defined as a lua function.

The second numkeys parameter is used to specify the number of key name parameters.

Starting from the third parameter (key name parameter key ), it represents those Redis keys (keys) used in the script. These key name parameters can be accessed in Lua through the global variable array KEYSstarting from 1as the base address KEYS[1],KEYS[2].

At the end of the command, additional parameters that are not key-name parameters arg [arg ...]can be accessed in lua through the global variable ARGVarray , and the subscript also starts from 1.

redis.call()Functions can be used in Lua scripts to execute redis commands.

Example of Jedis deduction inventory case call:

try (Jedis jedis = jedisPool.getResource()) {
    // 初始化商品id为100的库存
    jedis.set("product_stock_100", "10000");
    // @formatter:off
    String script = "local count =  redis.call('get',KEYS[1]) " +
            "local a = tonumber(count) " + 
            "local b = tonumber(ARGV[1]) " + 
            "if a >= b then " + 
            "redis.call('set',KEYS[1],a-b) " + 
            "return 1 " + 
            "end " + 
            "return 0";
    // @formatter:on
    Object decrResult = jedis.eval(script, Arrays.asList("product_stock_100"), Arrays.asList("100"));
    System.out.println(decrResult);
}
复制代码

**Note: **Don't have infinite loops and time-consuming operations in the lua script, otherwise **redis will block** and will not accept other commands, so be careful not to use the above.

Redis is a single-process single-threaded execution script, and the pipeline will not block redis.

Will Redis LUA Script Execute Command Rollback?

Using a lua script can achieve a certain atomicity when executing a series of redis commands (no new instructions will be inserted during the execution of multiple instructions in the lua script), but it cannot roll back the previous results when the command execution fails .

We use the following code snippet to verify, we clear the redis data before executing the code.

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> KEYS *
(empty array)
复制代码

Then execute the following code, the complete code pays attention to the official account and 一个程序猿的异常sends the keyword LUAGet .

try (Jedis jedis = jedisPool.getResource()) {
    // @formatter:off
    String script = " redis.call('SET', 'success','100') " 
                    // 模拟redis 出现异常信息,-1索引在bitmap不存在会报错
                    + " redis.call('SETBIT', 'bit_test','-1','1')  "
                    + " redis.call('SET', 'fail','100') " 
                    + " return 1";
    // @formatter:on
    Object eval = jedis.eval(script);
    System.out.println(eval);
}
复制代码

View the data in redis after execution:

127.0.0.1:6379> KEYS *
1) "success"
127.0.0.1:6379> get success
"100"
复制代码

Conclusion: Using the lua script can achieve a certain atomicity when executing a series of redis commands (no new instructions will be inserted during the execution of multiple instructions in the lua script), but it cannot roll back the previous results when the command execution fails .

Guess you like

Origin juejin.im/post/7088963946534666271