Redis is a very popular in-memory database used for data caching and high-frequency data storage. Most developers have probably heard that Redis can run Lua scripts, but probably don’t know when Redis needs Lua scripts.

I. Preconditions for reading this article

  • You can follow the instructions in this link to install Redis on your operating system
  • If you are not familiar with redis commands, check out redis Command References.

Why do YOU need Lua scripts

In short: Lua scripting provides a performance boost.

  • Many applications have multiple redis operations and multiple Redis commands, so you can use Redis in combination with Lua scripts for better performance.
  • In addition, the redis command contained in a Lua script has atomic properties, which can effectively avoid dirty data generated by multi-threaded operations when you are faced with redis database operations in high concurrency scenarios.

3. Learn Lua syntax

With all this talk, what can Lua do? Don’t panic! Lua is pretty simple, and if you’ve ever learned any programming language, it’s pretty easy to learn. Here are a few examples to learn:

3.1. A simple example

Lua scripts can be called by redis clients in various languages. Let’s use the redis cli to see the following command line:

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

Redis. call(‘set’, KEYS[1], ARGV[1])” is a string in a programming language. The EVAL command line is followed by the Lua script:

  1. The number of KEYS required by the Redis Lua script is only one [1], so the parameter immediately following the script is 1
  2. The Lua script requires the parameter KEYS[1], which in our case is key:name
  3. The Lua script requires the parameter ARGV[1], which in our case is value

The Lua script contains two sets of parameters: KEYS[] and ARGV[], with two array subscripts starting at 1. A good best practice to follow is to pass KEYS for redis operations and ARGV for Lua scripts.

After the above script is executed, we use the following Lua script to verify that our Lua script is executed correctly if the script returns “value”, which is the same as the key:name value we set earlier.

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

3.2. Take a close look at the contents of the Lua script

Our first Lua script consisted of a single statement that called redis.call

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

Therefore, in Lua script, you can execute the redis command through redis. Call. The first parameter of call method is the name of redis command.

Our second script doesn’t just execute a script, because executing the get command also returns the execution result. Notice that there is a return keyword in the script.

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

Of course, if only the above simple Lua script, it is better to use the command line directly. The actual Lua script we use is more complex than the one above, which is just a Hello World.

3.3. A more complicated example

I used Lua scripts to get the values of several keys in a certain order from a hash map. The corresponding order is saved in a Zset sort set, and data setting and sorting can be done through the following.

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 # Zadd order 1 key:3 2 key:1 3 key:2Copy the code

If you don’t know the 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
Copy the code

You should see the following output

"Value: 3" and "value: 1" "value: 2"Copy the code
  • [key:3, key:1, key:2]
  • Then unpack [key:3,key: 1,key:2] to key:3 key:1 key:2
  • Finally, execute hmget hkeys key:3 key:1 key:2 to obtain the above output

Lua script preloading

Redis can preload Lua scripts, you can use the script load command to preload Lua scripts into Redis.

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

After the preloading is complete, you should see the following output

"4 e6d8fc8bb01276962cce5371fa795a7763657ae"Copy the code

This is a unique hash string that represents the Lua script we just preloaded, which we can execute using the EVALSHA command. Such as:

evalsha 4e6d8fc8bb01276962cce5371fa795a7763657ae 1 key:name
Copy the code

The result of the execution is consistent with the following.

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

An example of modifying JSON data?

Some developers may sometimes save JSON data in Redis, but let’s not talk about whether this is a good idea, but how to modify JSON data using Lua scripts.

Normally, you need to modify a JSON Object. You need to retrieve it from Redis, parse it, change the key, and then serialize it and save it to Redis. There are several problems with this:

  1. Atomicity is not guaranteed in high concurrency scenarios, and another thread can change the JSON data between the current thread’s Object acquisition and setting operations. In this case, updates will be lost.
  2. Performance issues. If you make such changes frequently and the JSON data is quite large, this can be a performance bottleneck for your application. Because you’re constantly fetching and storing data.

By implementing the above logic in Lua, because the Lua script of Redis is executed on the server side, on the one hand, it can ensure the atomicity of operation and solve the problem of high concurrency loss and update, on the other hand, it can save network transmission and improve performance.

Let’s save a test JSON string to Redis: obj

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

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 bar2Copy the code
  • local obj = redis.call(“get”,KEYS[1]); KEYS[1]=obj = ‘{“a”:”foo”,”b”:”bar”}’

  • local obj2 = string.gsub(obj,”(” .. ARGV[1] .. “\”) ([^}] +) “, “% 1”.. ARGV[2]); . Is a string concatenation for Lua scripts; We use the RegEx pattern to match the key and replace its value, and make up the lesson if the expression is not familiar; %1″ represents the first matched substring, “%1”.. ARGV[2] is equal to “b”:”bar2″ and is replaced with gsub.

  • The result of obj’s JSON object is as follows:

{"a":"foo","b":"bar2"}
Copy the code

Six, summarized

I recommend using Lua scripts only if you can prove that it leads to better performance. If you just want to ensure atomicity of redis operations, you can use transactions. You don’t have to use Lua scripts.

Also, Redis Lua scripts should not be too long. Because the script locks the object while it runs, all other operations are waiting for it to complete. If Lua scripts take a long time to execute, this can lead to bottlenecks rather than performance improvements. The Lua script stops when a timeout is reached (5 seconds by default).

Welcome to my blog, where there are many fine collections

  • This article is reprinted with a credit (must be accompanied by a link, not only the text) : Antetokounmpo blog.

Feel helpful to you, help me like, share! Your support is my inexhaustible creative power! . In addition, the author recently a period of time output as follows boutique content, looking forward to your attention.

  • Spring Boot2.0 by Hand
  • Spring Security- JWT-OAUTH2
  • RBAC Authority Management System for Actual Combat Front-end and Back-end Separation
  • “Actual SpringCloud Micro-service from Bronze to King”
  • VUE Series