Quick Start Redis Calling Lua Scripts and Introduction to Usage Scenarios

Redis is a very popular memory database, often used for data caching and high-frequency data storage. Most developers may have heard that redis can run Lua scripts, but may not know under what circumstances redis needs to use Lua scripts.

1. Prerequisites for reading this article

2. Why do you need Lua scripts

In short: Lua scripts bring performance improvements .

  • Many application service tasks include multiple redis operations and the use of multiple redis commands. At this time, you can use Redis combined with Lua scripts, which will bring better performance to your application.
  • In addition, the redis command contained in a Lua script is atomic. When you are faced with redis database operations in high concurrency scenarios, you can effectively avoid dirty data generated by multi-threaded operations.

Three, learn some Lua syntax

Having said so much, what will Lua do? Don't panic! Lua is actually very simple. If you have ever learned any programming language, learning Lua is very easy. Let me give you a few examples to learn:

3.1. A simple example

Lua scripts can be invoked through redis clients in various languages. Let's simply use it. redis-cliLook at the redis command line below:

eval "redis.call('set', KEYS[1], ARGV[1])" 1 key:name value

The EVAL command line is followed by a Lua script:, "redis.call('set', KEYS[1], ARGV[1])"put in the programming language is a string, and the three parameters following the Lua script string are:

  1. The number of KEYS required by the redis Lua script is only one KEYS[1], so the parameter value immediately after the script is 1
  2. The parameter value of the parameter KEYS[1] required by the Lua script, in our example the value is key:name
  3. The parameter value of the parameter ARGV[1] required by the Lua script, in our example the value is value

The Lua script includes two sets of parameters: KEYS[] and ARGV[] , the subscripts of the two arrays start from 1. A best practice worth following is to pass the key required for redis operations through KEYS as parameters, and pass the parameters required by other Lua scripts through ARGV.

After the execution of the above script is completed, we use the following Lua script to verify. If the return value of the script is "value", which is the same as the value of key:name we set before, it means that our Lua script has been executed correctly .

eval "return redis.call('get', KEYS[1])" 1 key:name

3.2. Take a closer look at the content in the Lua script

Our first Lua script contains only one statement, callingredis.call

redis.call('set', KEYS[1], ARGV[1])

So in the Lua script, you can redis.callexecute the redis command. The first parameter of the call method is the name of the redis command. Because we are calling the redis set command, we need to pass the key and value parameters.

Our second script not only executes a script, because executing the get command also returns the execution result. Note that there is a return keyword in the script.

eval "return redis.call('get', KEYS[1])" 1 key:name

Of course, if it is just a simple Lua script like the above, it is more convenient to use the command line directly. The Lua script we actually use will be more complicated than the above. The above Lua script is just a Hello World.

3.3. Examples of complicated points

I have used a Lua script to get the values ​​corresponding to several keys in a certain order from a hash map. The corresponding order is saved in a zset sorting set, and the data setting and sorting can be completed by the following.

# 设置hkeys为键Hash值
hmset hkeys key:1 value:1 key:2 value:2 key:3 value:3 key:4 value:4 key:5 value:5 key:6 value:6
# 建一个order为键的集合,并给出顺序
zadd order 1 key:3 2 key:1 3 key:2

If you don’t know the function of hmset and zadd commands, you can refer to hmset and zadd

Execute the following Lua script

eval "local order = redis.call('zrange', KEYS[1], 0, -1); return redis.call('hmget',KEYS[2],unpack(order));" 2 order hkeys

You will see the following output

“value:3”
“value:1”
“value:2”
  • Get the data in the order collection through zrange, namely: [key:3, key:1, key:2]
  • Then use the unpack function to convert [key:3, key:1 ,key:2] into key:3 key:1 key:2
  • Finally execute hmget hkeys key:3 key:1 key:2, so the above output result is obtained

Four, Lua script preloading

Redis can preload Lua scripts, and Lua scripts can be preloaded into redis through the script load command.

script load "return redis.call('get', KEYS[1])"

After preloading is complete, you will see the following output

“4e6d8fc8bb01276962cce5371fa795a7763657ae”

This is a unique hash string. This hash represents the Lua script we just preloaded. We can execute the script through the EVALSHA command. Such as:

evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name

The result of the execution is consistent with the following.

eval "return redis.call('get', KEYS[1])" 1 key:name

5. An example of modifying JSON data?

Some developers may save JSON data in Redis sometimes. Let's not say whether this is a good way. Let's just talk about how to modify JSON data through Lua scripts.

Under normal circumstances, you need to modify a JSON Object, you need to query it back from redis, parse it, modify the key value, and then serialize it and save it in redis. There are several problems with this:

  1. In high-concurrency scenarios, atomicity cannot be guaranteed. Another thread can change this JSON data between the current thread's acquisition and setting of Object operations. In this case, the update will be lost.
  2. Performance issues. If you frequently make such changes and the JSON data is quite large, this may become a performance bottleneck for the application. Because you frequently fetch and store data.

By implementing the above logic in Lua, because redis's Lua script is executed on the server side, on the one hand, it can ensure the atomicity of operations and solve the problem of high concurrency lost updates. On the other hand, it saves network transmission and improves performance.

Next, we save a test JSON string to redis:obj

set obj '{"a":"foo","b":"bar"}'

Now, let's run our script:

EVAL 'local obj = redis.call("get",KEYS[1]); local obj2 = string.gsub(obj,"(" .. ARGV[1] .. "\":)([^,}]+)", "%1" .. ARGV[2]);  return redis.call("set",KEYS[1],obj2);' 1 obj b bar2
  • local obj = redis.call("get",KEYS[1]); Where KEYS[1]=obj, so the return valueobj= '{"a":"foo","b":"bar"}'
  • local obj2 = string.gsub(obj,"(" .. ARGV[1] .. "\":)([^,}]+)", "%1" .. ARGV[2]);, ..Is the string concatenation symbol of Lua script; we use RegEx pattern to match the key and replace its value. If you are not familiar with the expression, make up your own lesson; "%1" means the first matched substring, "%1 ".. ARGV[2] is equal to "b":"bar2", and use gsub to replace it.
  • Finally, the result is returned, objand the result of the JSON object is as follows:
{"a":"foo","b":"bar2"}

Six, summary

I recommend using Lua scripts only if you can prove that it can bring better performance. If you just want to ensure the atomicity of redis operations, you can use transactions . It is not necessary to use Lua scripts.

In addition, the redis Lua script should not be too long. Because when the script is running, it is equivalent to locking the operated object, and other operations are waiting for it to complete. If the Lua script takes a considerable amount of time to execute, it may cause a bottleneck instead of improving performance. The Lua script stops after the timeout is reached (5 seconds by default).

Welcome to follow my blog, there are many boutique collections

  • This article is reproduced indicate the source (en must not turn only the text): letters Gebo off .

If you think it is helpful to you, please like and share it for me! Your support is my inexhaustible creative motivation! . In addition, the author has output the following high-quality content recently, and I look forward to your attention.

Guess you like

Origin blog.csdn.net/hanxiaotongtong/article/details/114110225