Using Lua Scripts for Redis Transactions
Redis transactions can be implemented in two ways: with MULTI, or with Lua scripts. Lua scripts are simpler, require fewer client-server interactions, and can be cached by Redis, which makes them especially useful in performance-sensitive scenarios.
Lua Scripts
Official documentation: https://redis.io/commands/eval
Redis provides two commands for executing Lua scripts: eval and evalsha.
The syntax of eval is:
Explanation:
- The second string argument is the Lua script itself.
KEYSandARGVare reserved keywords. 2means the script references two keys.KEYSis used to pass Redis keys into the script.ARGVcontains the remaining arguments after the keys, indexed from 1.returnspecifies the returned value.
If the server has already cached the Lua script, you can use evalsha instead. This reduces payload size when the script body is large.
Starting from Redis 3.2.0, Redis also ships with a Lua debugger: https://redis.io/topics/ldb
Example
| |
This code works as follows:
- It creates a Redis hash named
userToken:{accountId}for each user if it does not already exist, and initializes thelatestfield to0. - If
howmanyis not zero, it reserves that many tokens for the user by:- incrementing
latestand using the new value as the hash field - writing the reserved timestamp into the hash
- repeating this in a loop
- incrementing
- It writes the final
latestvalue back to the hash and returns it.
One important detail is the trailing or 0 in local sid=redis.call('HGET',KEYS[1],'latest') or 0;. Without it, sid may become a boolean value when the field does not exist, and arithmetic on it will fail with an error like this:
| |
Additional Notes
Lua conditionals
The syntax for conditionals in Lua is:
Without an else, it can be shortened to:
Lua also supports elseif.
Integers and strings
Redis keys are strings, while values can be integers. If your key itself looks numeric and you compare it directly with an integer value, you may get unexpected results because the key is still a string. If you need numeric comparison, use one of these approaches:
- Convert with
tonumber - Force conversion with
+0
JSON handling
Lua scripts inside Redis have the cjson library built in, so you can use cjson.encode and cjson.decode directly.
An encode example:
decode is similar: