preface
Good brothers,
Redis
The thirteenth of the series, aboutRedis
Under theLua
The script. All right, I put my cards on the table. This one I was forced to write, is really hard (no driving ah). Because I didn’t know Lua very well, and thenNovice tutorialA meal of operation, but also kind of getting started. It’s worth noting that there are a lot of similarities between programming languages.
The other thing is why I don’t understandLua
Still want to write such an article, not owe ah. The main idea is to familiarize yourself with this and then understand the distributed transaction frameworkRedisson
It’s kind of a logic. Or very helpful, after reading this good brother probably can knowRedisson
It’s a logical one. It’s full of dry goods.
That is likeLua
Script installation, configuration and other related basic male I don’t get, good brother tutorial (rookie tutorial, the name is drunk, completely does not conform to good brother (giant) identity ah) have, at that time or some design to the basic, or jump too big, afraid of good brothers can not stand ah.
Lua foundation
Lua provides several data types: Booleans (Booleans), numbers (numbers), strings (strings), and tables (tables). Lua’s basic data types and logic processing will be discussed below (if there is a Lua environment). For more information, please visit Lua’s official website or beginner’s tutorial.
1 string
- enter the Lua
lua -i
-- Lua version is relevant
Lua 5.14. Copyright (C) 1994- 2008. Lua.org, PUC-Rio
Interactively execute a command that defines a string of data, where local means val is a local variable and global if there is no local.
>local string val = "world"
-- Print out
> print(val)
world
Copy the code
2 array
Note that Lua’s array indices start at 1
Define an array
>local tables myArray = {"redis"."jedis".true.88.0}
Print the second element of the array
> print(myArray[2])
jedis
Copy the code
3 the hash
If you want to use hash-like functionality, you can also use the tables type. The following code defines a table with each element containing a key and value, where.. Is to concatenate two strings
-- Define a Hash
> local tables user_1 = {age = 27, name = "Dawn"}
-- Prints the name
> print("user_1 name is ". user_1["name"])
user_1 name is Dawn
Copy the code
4 a for loop
The following code evaluates the sum from 1 to 100, with the keyword for ending with end.
> local int sum = 0
> for i = 1.100
>> do
>> sum = sum + i
>> end
The output is 5050
> print(sum)
5050
Copy the code
Iterate over and print the values of the myArray array in the second example
> for i = 1, #myArray
>> do
>> print(myArray[i])
>> end
Copy the code
5 the while loop
The following code also evaluates the sum from 1 to 100 using a while loop, which also ends with end.
> local int sum = 0
>> local int i = 0
>> while i <= 100
>> do
>> sum = sum +i
>> i = i + 1
>> end
The output is 5050
> print(sum)
5050
Copy the code
6 if else
To determine whether the array contains jedis, print true if it does, noting that if ends with end and if followed by then.
> local tables myArray = {"redis"."jedis".true.88.0} > >for i = 1, #myArray
>> do
>> if myArray[i] == "jedis"
>> then
>> print("true") > >break
>> else
--do nothing
>> end
>> end
Copy the code
7 Function Definition
In Lua, a function starts with function and ends with end, funcName is the function name and the middle part is the function body.
Format -
> function funcName(a)
>> ...
>> end
The contact function concatenates two strings
> function contact(str1, str2)
>> return str1 .. str2
>> end
-- Function call
> print(contact("hello "."Dawn"))
hello Dawn
Copy the code
Lua is used in Redis
There are two ways to execute Lua scripts in Redis: eval and evalsha.
1 eval
Through the built-inLua
The interpreter can be usedEVAL
Command (can also be usedredis-cli
的--eval
Parameters) onLua
The script parses. One thing to watch out for is executionLua
Also can makeRedis
Blocking.
# # formatEval Number of keys in a script Key list Parameter list## uses key lists and parameter lists to provide more flexibility for Lua scripts
127.0.0.1:6379> eval 'return "hello " .. KEYS[1] .. ARGV[1]' 1 redis world
"hello redisworld"
Copy the code
2 evalsha
evalsha
The method is also divided into two steps, the first is toLua
The script loads intoRedis
Server to get the scriptSHA1
Check code. Then use theevalsha
Command to useSHA1
As an argument, the corresponding can be performed directlyLua
The script. This has the advantage of avoiding sending each timeLua
The overhead of scripts, which are also resident on the server, and the reuse of script functionality. The disadvantage is how to manage these scripts and commands too much will take upRedis
In the memory.
Define a Lua file in the current directory
vim myLua.lua
Add the command to the file and save it
return "hello ". KEYS[1].. ARGV[1]
The script load command loads the contents of the script into Redis memory
redis-cli script load "$(cat myLua.lua)"
## 2. Enter the Redis client
redis-cli
## 3. evalsha executes script formatEvalsha Script SHA1 Value Number of keys Key list Parameter list## 4. Execute mylua.lua
127.0.0.1:6379> evalsha 5ea77eda7a16440abe244e6a88fd9df204ecd5aa 1 redis world
"hello redisworld"
Copy the code
Lua Redis API
Lua can access Redis using the redis.call and redis.pcall functions. The difference between redis. Call and redis. Pcall is that if redis. Call fails, an error is returned at the end of script execution, while redis. Choose the corresponding function according to the actual situation. The following code calls the redis set and get operations using redis. Call
-- The format command refers to corresponding commands such as set/get, followed by key and val
redis.call(command, key, arg)
redis.call("set"."hello"."world")
redis.call("get"."hello")
Copy the code
Use Redis’ eval to perform the effect
127.0.0.1:6379> eval 'return redis.call("get", KEYS[1])' 1 hello
"world"
Copy the code
Execute the Lua file
When Lua scripts have a lot of logic, it becomes obvious that using the above method is not appropriate, so it is necessary to write a separate Lua file. The following code logic sets a key and value in Redis. If value equals hello, return 1. If value equals world, return 2
## 1. Define a Lua file and edit it
vim myRedisLua.lua
## 2. Add simple logic
redis.call('set', KEYS[1], ARGV[1])
local val = redis.call('get', KEYS[1])
if "hello" == val then
return 1
end
if "world" == val then
return 2
end
## 3. Execute this script in Redis
## example, return 1
redis-cli --eval myRedisLua.lua key1 , hello
(integer) 1
## example, return 2
redis-cli --eval myRedisLua.lua key1 , world
(integer) 2
Copy the code
Redis Lua script management
1 Load Lua into Redis
Load Lua scripts into Redis using script Load, as demonstrated above
# # format
script load script
Copy the code
2 Check whether SHA1 exists in Redis
Use script exists to determine whether the corresponding script has been loaded into Redis. The returned result represents SHA1 [SHA1… The number of loads into Redis memory.
# # format
scripts exists sha1 [sha1... ]# # chestnuts
127.0.0.1:6379> script exists 5ea77eda7a16440abe244e6a88fd9df204ecd5aa
1) (integer) 1
Copy the code
3 Clear all Lua scripts loaded in Redis memory
Use the script flush command to flush all Lua scripts that have been loaded into Redis memory.
# # format
script flush
Check if the script exists first
127.0.0.1:6379> script exists 5ea77eda7a16440abe244e6a88fd9df204ecd5aa
1) (integer) 1
Perform a clear operation
127.0.0.1:6379> script flush
OK
## Recheck no longer exists
127.0.0.1:6379> script exists a5260dd66ce02462c5b5231c727b3f7772c0bcc5
1) (integer) 0
Copy the code
4 Stop the Lua script
If the Lua script is time-consuming or even problematic, the execution of the Lua script will block Redis until the execution of the Lua script is complete or an external intervention will end the execution. Then you can use script kill to kill the executing Lua script. In addition, Redis provides a lua-time-limit parameter. The default value is 5 seconds. This is the “timeout” of the Lua script, but this timeout is only used to send BUSY to other command calls when the lua script exceeds the lua-time-limit. However, script execution on the server and client will not be stopped. Therefore, when lua-time-limit is reached, other clients will receive “Busy Redis is Busy running a script” error when executing normal commands. The script prompts the busy to be killed with either script kill or shutdown nosave. Here’s a simple demonstration
## Write a lua script in an infinite loop and execute it in the Redis client
127.0.0.1:6379> eval 'while 1==1 do end' 0
Error message is returned. At this time, Redis is blocked and cannot process normal calls. You can choose to continue to wait.
## But more often you need to kill the script quickly. Using shutdown Save is obviously not appropriate, so script kill is selected, and when script kill is executed, the client call resumes
127.0.0.1:6379> get test
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
## Start another client and stop the script execution
127.0.0.1:6379> script kill
OK
127.0.0.1:6379> get k1
"11"
Copy the code
Usage scenarios
- Distributed locking frame
Redisson
The idea is to useLua
The script. - Active user judgment: Determine whether a game user is an active user. If the user meets the criteria, the number of active users is +1.
- Simple DDOS defense: Limits the number of access attempts from the same IP address within n seconds.
- Data analysis, real-time average statistics.
- Many other specific business scenarios (which I haven’t used, logical judgment data generally don’t exist in Redis).
Lua vs. Pipeline
Not familiar with Pipeline good brother can see Redis Pipeline this article is enough.
- In terms of performance, both modes are similar in that they pack the commands all at once, reducing the round-trip time.
- Atomically speaking,
Pipeline
Nonatomic,Lua
Student: Atomic. - In terms of flexibility,
Pipeline
Only native command packaging is supported, whereas likeLua
Can support complex business logic, more flexibility. Pipeline
Cluster mode is not supported and can only be used on one Redis node at a time. whileLua
Yes, clustering is supported.Pipeline
withLua
None of them support transactions.Pipeline
Generally there are client real-time packaging commands, whileLua
Scripts can be stored inRedis
To improve the reuse rate.
conclusion
The main benefits of using Lua scripts are:
Lua
The script inRedis
Is in theAtomic executionNo other commands are inserted during execution. The above to tell themeval
The picture of the command is a good explanation.Lua
Scripts help developers and operations create their own custom commands and keep them residentRedis
Memory, to achieve the effect of reuse.Lua
Scripts can package multiple commands at a time, effectively reducing network overhead.Lua
Scripts can adapt to more complex business scenarios (Like distributed locks), can be embedded in JAVA, C# and other programming languages, support cross-platform interaction of different operating systems.- Relatively speaking,
Lua
Simple and powerful, low resource usage, support procedural and objectified programming language. It’s important to note that,Lua
Can bring a lot of advantages. But it’s also somewhat more demanding for good brothers to useLua
The premise of scripts is familiarityLua
Basic syntax and usage. On the other hand, in executionLua
When the script,Redis
It’s blocked. So on the one handLua
andPipeline
Also, don’t include too many commandsLua
Do not execute logic that is too time-consuming business logic, which may be due toLua
The script logic was faulty, creating an endless loop that led to the entireRedis
Service unavailable. soLua
Scripts are good, but it’s hard to imagine how damaging they can be when used improperly, so make sure you use them before you doLua
Is correct.
That’s the end of this issue. Welcome to leave your comments in the comments sectionAsk for attention, ask for likes
Redis Bitmaps: How do you know about Redis