Redis series of Lua script integration

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.callfunction 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.callfunction 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.pcallfunctions with the redis.callsame functions . The only difference is that when an error occurs in the command execution, the error redis.pcallwill be logged and the execution redis.callwill 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.confconfiguration lua-time-limit 5000file: . 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

  1. Reduce network overhead: multiple requests can be sent at one time in the form of scripts, reducing network delays and the number of requests
  2. 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
  3. Code reuse: the script sent by the client will be permanently stored in Redis, and other clients can be reused
  4. Fast speed: JIT compiler can significantly improve performance
  5. 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)
  6. 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:

  1. 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
  2. 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)
  3. 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 )
  4. 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 LOADthe 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

Guess you like

Origin blog.csdn.net/lonelymanontheway/article/details/107217510