Overview
Redis supports Lua from version 2.6. Lua scripts can be compiled and run on any platform; a script is an atomic transaction.
take
Official website , a small and powerful scripting language. Designed to be embedded in the application program, provide flexible extension and customization functions for the application program, and can call each other with C/C++ code. It can also be used as a configuration file. The Lua-JIT project aims to provide just-in-time compilation on a specific platform.
characteristic:
- The variable name has no type, only the value has the type, and the variable name can be bound to any type of value at runtime;
- The language only provides one data structure: table, mixed array + hash, and any type of value can be used as key and value. Provide a consistent and expressive table structure syntax, making Lua very suitable for describing complex data;
- Function is a first-class type, supporting anonymous functions and regular tail recursion (proper tail recursion);
- Support lexical scoping and closure;
- Provide thread type and structured coroutine mechanism, which can facilitate the realization of cooperative multitasking;
- The program text in the form of string can be compiled and loaded into the virtual machine for execution during the runtime;
- Provide dynamic meta-mechanism through metatables and metamethods, which allows the program to change or expand the default semantics of the grammatical facility as needed when the program is running;
- Can easily use tables and dynamic meta-mechanisms to implement prototype-based object-oriented models;
- Starting from version 5.1, a complete module mechanism is provided to better support the development of large-scale applications.
integrated
Redis supports most Lua standard libraries:
Library name | Description |
---|---|
Base | Provide some basic functions |
String | Provides functions for string manipulation |
Table | Provides functions for table operations |
Math | Provide mathematical calculation functions |
Debug | Provide functions for debugging |
In addition, you can use the redis.call
function to call the redis command in the script :
redis.call('set', 'foo', 'bar')
local value=redis.call('get', 'foo') --value的值为bar
There are 5 types of return values of Redis commands, and the redis.call
function converts these 5 types of return values into the corresponding Lua data types:
Redis return value type | Lua data types |
---|---|
Integer | Number type |
String | String type |
Multi-line string | table type, array form |
status | Table type (only one ok field stores status information) |
error | Table type (only one err field stores error information) |
Empty result | false |
Redis also provides redis.pcall
functions with the redis.call
same functions . The only difference is that when an error occurs in the command execution, the error redis.pcall
will be logged and the execution redis.call
will continue, but the error will be returned directly and the execution will not continue. The return statement can be used in the script to return the value to the client. If the return statement is not executed, it will return nil by default.
Configuration
In the redis.conf
configuration lua-time-limit 5000
file: . In order to prevent a script execution time from being too long, causing Redis to fail to provide services, Redis provides the lua-time-limit parameter to limit the maximum running time of the script, which is 5 seconds by default. When the script running time exceeds this limit, Redis will start to accept other commands but will not execute them (to ensure the atomicity of the script, because the script is not terminated at this time), but will return a "BUSY" error.
Advantage
- Reduce network overhead: multiple requests can be sent at one time in the form of scripts, reducing network delays and the number of requests
- Atomic operation: Redis will execute the entire script as a whole without being inserted by other commands in the middle. No need to worry about race conditions, no need to use transactions
- Code reuse: the script sent by the client will be permanently stored in Redis, and other clients can be reused
- Fast speed: JIT compiler can significantly improve performance
- Portable: Lua is based on C, as long as it is a platform with ANSI C compiler can be compiled, even the browser can also be used perfectly (translated into JS)
- The source code is small and exquisite: 2w lines of C code, can be compiled into 182K executable files, fast loading, fast running
command
Redis supports the Lua script function, and several new commands (except script debug, which is a command introduced in Redis 3.2).
eval
Reference: eval document
Command parameters: EVAL script numkeys key [key ...] arg [arg ...]
Command interpretation:
- The script parameter is a Lua script program that will be run in the context of the Redis server. This script does not (and should not) be defined as a Lua function
- The numkeys parameter specifies the number of key name parameters; when the script does not require any parameters, this parameter cannot be omitted (set to 0)
- The key name parameter
key [key ...]
represents the Redis keys used in the script, which can be accessed in Lua through the global variable KEYS array with 1 as the base address (KEYS[1], KEYS[2], and so on ) - Additional parameters
arg [arg ...]
can be accessed in Lua through the global variable ARGV array. The access form is similar to the KEYS variable (ARGV[1], ARGV[2], etc.)
Demo:
1608(10.114.31.113:6408)> eval "return {KEYS[1],ARGV[1]}" 1 testKey testValue
1) "testKey"
2) "testValue"
1608(10.114.31.113:6408)> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 username age jack 20
"CROSSSLOT Keys in request don't hash to the same slot"
Reference: redis-cross-slot-error , to the effect that in a distributed Redis cluster, keys will be divided into different slots, and different nodes will have a subset of hash slots.
In a cluster topology, the keyspace is divided into hash slots. Different nodes will hold a subset of hash slots.Multiple keys operations, transactions, or Lua scripts involving multiple keys are allowed only if all the keys involved are in hash slots belonging to the same node.
Redis cluster implements all non-distributed versions of single-key commands. Multiple key operations, transactions, or lua scripts calling multiple keys are allowed, provided that all the called keys are in the hash slot of a node.
Solution
Use Hash Tags to force all keys to belong to one node.
file
When the lua script is long, it can be placed in a file,
$ redis-cli --eval path/to/redis.lua KEYS[1] KEYS[2] ... , ARGV[1] ARGV[2] ...
-eval, tells redis-cli to read and run the following lua script
KEYS and ARGV. The spaces on both sides of the',' cannot be omitted.
EVALSHA
Reference: evalsha document
In the case of a long script, if the entire script needs to be passed to Redis every time the script is called, it will take up more bandwidth. To solve this problem, Redis provides the EVALSHA command, which allows developers to execute the script through the SHA1 summary of the script content. The usage of this command is the same as EVAL, except that the script content is replaced with the SHA1 summary of the script content.
Redis will calculate the SHA1 summary of the script when executing the EVAL command and record it in the script cache. When executing the EVALSHA command, Redis will look up the corresponding script content from the script cache according to the provided summary, and execute the script if it finds it, otherwise it will return an error: "NO SCRIPT No matching script. Please use EVAL."
Command parameters: EVALSHA sha1 numkeys key [key ...] arg [arg ...]
sha1 is SCRIPT LOAD
the SHA1 check code generated by the pass.
The comparison
eval command adds the script to the script cache and immediately evaluates the entered script.
The evalsha command adds the script to the script cache , but does not execute the script immediately.
SCRIPT LOAD
Reference: script-load document
Adds the script to the cache, but does not execute it, and returns the SHA1 summary of the script.
SCRIPT EXISTS
Reference: script-exists document
Determine whether the script has been cached.
SCRIPT FLUSH
Reference: script-flush document
Clear the script cache, redis adds the SHA1 summary of the script to the script cache and it will be permanently retained. Manually use the SCRIPT FLUSH command to clear the script cache.
SCRIPT KILL
Reference: script-kill document
Forcefully terminate the execution of the current script. However, if the current execution of the script writes redis data, the SCRIPT KILL command will not terminate the running of the script to prevent the script from executing only part of it. All commands in the script are either executed or not executed.
SCRIPT DEBUG
Reference: script-debug document
Coding example
Jedis integrates Lua
Translate the eval command demonstrated above into Java code based on Jedis:
@Test
public void testLuaWithJedis() {
Jedis jedis = new Jedis("10.114.31.113", 6408);
String luaStr = "return {KEYS[1],ARGV[1]}";
Object result = jedis.eval(luaStr, Lists.newArrayList("testKey"), Lists.newArrayList("testValue"));
}
But an error was reported.
JedisMovedDataException: MOVED 165 10.114.31.113:6407
Solution:
Using Lua scripts in Spring Boot
spring-boot-starter-data-redis dependency, use redisTemplate
The variables in the lua script must be local, not global variables, otherwise an error will be reported. See http://doc.redisfans.com/script/eval.html#id6 for details
Use DefaultRedisScript to load lua scripts
. Configure a DefaultRedisScript singleton in the application context to avoid repeated creation of the script's SHA1 when each script is executed:
@Bean
public DefaultRedisScript<Boolean> redisScript() {
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/checkandset.lua")));
redisScript.setResultType(Boolean.class);
return redisScript;
}
reference
redis-lua-script
redis-cross-slot-error
https://blog.csdn.net/u011943534/article/details/82717253