Introduction to the
Redis from version 2.6 introduced the use of Lua programming language for server-side scripting capabilities, this feature allows users to perform a variety of operations directly within Redis, thereby simplifying code and improving performance. P248
Add new functionality without writing C codeP248
By scripting Redis using Lua, we can avoid some common pitfalls that slow down development or degrade performance. P248
Load the Lua script into RedisP249
SCRIPT LOAD
The script is loaded into Redis by the command, which takes a Lua script as a string, stores it for later use, and returns the SHA1 checksum of the stored scriptEVALSHA
The command invokes the previously stored script, which receives the SHA1 checksum of the script and all the parameters required by the scriptEVAL
The command directly executes the specified script, which receives the script string along with all the parameters required by the script. In addition to executing the script, this command also caches the script to the Redis server
Due to Lua’s data incoming and outgoing restrictions, Lua and Redis need to convert each other. Because scripts can produce ambiguous results when returning various types of data, we should try to return strings explicitly. P250
We can find conversion tables between the different types of Redis and Lua in the official documentation:
The Redis type is converted to Lua type
Redis | Lua |
---|---|
integer reply | number |
bulk reply | string |
multi bulk reply | table (may have other Redis data types nested) |
status reply | table with a single ok field containing the status |
error reply | table with a single err field containing the error |
Nil bulk reply | false boolean type |
Nil multi bulk reply | false boolean type |
Lua type is converted to Redis type
Lua | Redis |
---|---|
number | integer reply (the number is converted into an integer) |
string | bulk reply |
table (array) | multi bulk reply (truncated to the first nil inside the Lua array if any) |
table with a single ok field | status reply |
table with a single err field | error reply |
boolean false | Nil bulk reply |
boolean true | integer reply with value of 1 |
Create a new status messageP251
- Lua scripts follow a single Redis command as well
MULTI
/EXEC
Like transactions, they are atomic operations - Lua scripts that have been structurally modified cannot be broken
- Do not execute any write commands on read-only scripts: scripts can be run over time in pairs
lua-time-limit
Option to execute after the specified timeSCRIPT KILL
Command to kill the script that is running - Script with command writing: Killing the script will cause Redis to store data in an inconsistent state. In this case
- Do not execute any write commands on read-only scripts: scripts can be run over time in pairs
Use Lua to override locks and semaphoresP254
If we don’t know in advance which keys will be read and written, WATCH/MULTI/EXEC transactions or locks should be used instead of Lua scripts. Therefore, reading or writing a key in a script that is not recorded in the KEYS parameter may cause incompatibility or failure when the application is migrated to the Redis cluster. P254
Lua scripts are no longer needed to obtain locks. You can use SET and use PX and NX options to SET a value with an expiration time when the key does not exist. To ensure that you can obtain the lock when releasing the lock, you need to use the Lua script. Related code has been implemented in the implementation of autocomplete, distributed lock and counting semaphore.
removeWATCH
/MULTI
/EXEC
The transactionP258
In general, if only a few clients attempt to modify the data monitored by the WATCH command, the transaction can usually complete without significant conflicts or retries. However, if an operation requires several communication round trips, or if the probability of an operation colliding is high, or if the network latency is high, the client may need to retry many times to complete the operation. P258
Using Lua scripts instead of transactions not only ensures successful execution of any client attempt, but also reduces communication overhead and dramatically improves TPS. Lua scripts are also significantly faster than fine-grained locking versions because there are no multiple communication round trips.
Lua scripts can provide huge performance benefits and can simplify code significantly in some cases, but run inside Redis but Lua scripts can only access data that is within Lua scripts or within Redis databases. Locks or WATCH/MULTI/EXEC transactions do not have this limitation. P263
Shard the list using LuaP263
The composition of a shard listP263
In order to perform push and eject operations on both ends of the shard list, the ID of the first shard and the ID of the last shard in the list need to be recorded during the construction of the shard list in addition to storing the shards that compose the list. When the shard list is empty, the shard ID stored by the two strings will be the same. P263
Each shard that makes up the shard list is named < listName >:
and assigned in order. Specifically, if the program always pops elements from the left and pushes them in from the right, the last allocated index will grow, and the ID of the new shard will become larger and larger. If the program always pops elements from the right and pushes them in from the left, the index of the first shard will decrease and the ID of the new shard will become smaller and smaller. P264
When a shard list contains multiple lists, the list at either end of the shard may be filled, but the other lists between the two ends are always filled. P264
Push the element into the shard listP265
The Lua script uses LPUSH/RPUSH to find the first or last shard in the list and then pushes the element into the list. If the number of shards has reached the upper limit (the value -1 of list-max-ziplist-entries in the configuration can be used as the upper limit), A new shard is automatically generated, pushed in, and the shard ID of the first or last shard is updated. When the push operation completes, it returns the number of pushed elements. P265
Eject elements from the shardP266
The Lua script finds the first or last shard of the list using the command LPOP/RPOP, and pops an element from the shard if the shard is not empty. If the list does not contain any more elements after the pop operation, Then the program will modify the string key that records the shard information at both ends of the list (note that the string key will be modified only when the shard at the list end is empty, while the whole list is empty) P267
Perform blocking pop-up on the shard listP267
I don’t understand this part of the book, and I don’t know why I need the fancy operation in the book to complete it.
Personally, the blocking pop-up of the shard list does not need the blocking pop-up of the list itself. We can continuously execute the operation of the pop-up element implemented by the above Lua script. If the pop-up succeeds, it will return directly; if the pop-up fails, we will continue to perform the pop-up operation after 1 ms sleep until the pop-up succeeds or reaches the timeout time. So we only operate on Redis in Lua script, atomicity guarantees that the elements at both ends of the shard list will pop up.
This article is published on GitHub: Reading-notes/Redis-in-Action