参考:
Redis从2.6.0版本开始支持Lua脚本,通过在服务器嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务器端原子地执行多个Redis命令。
1.使用Lua脚本的好处:
2.相关命令:
EVAL script numkeys key [key ...] arg [arg ...]
KEYS
数组访问,下标从1开始,如: KEYS[1]、KEYS[2]ARGV
数组访问,下标从1开始,如:ARGV[1]、ARGV[2]示例:
(1)使用KEYS
数组、ARGV
数组
redis> eval "return {KEYS[1], KEYS[2], ARGV[1], ARGV[2]}" 2 key1 key2 arg1 arg2
1) "key1"
2) "key2"
3) "arg1"
4) "arg2"
(2)输出list中所有元素
redis> rpush nums 1 2 3
(integer) 3
redis> eval "return redis.call('lrange', KEYS[1], 0, -1)" 1 nums
1) "1"
2) "2"
3) "3"
(3)集合去重
使用lua脚本文件方式,在命令行里执行,和在redis里执行不太一样,命令如下:
redis-cli --eval lua_file key1 key2 , arg1 arg2 arg3
示例:
redis> sadd nums 1 2 3
(integer) 3
redis> smembers nums
1) "1"
2) "2"
3) "3"
-- key
local key = KEYS[1]
-- 所有参数
local args = ARGV
-- 初始化result
local result = {}
-- 判断元素是否存在
for m, n in ipairs(args) do
local is_repeat = redis.call("sismember", key, n)
if (is_repeat) then
table.insert(result, 1, n)
end
end
return result
$ redis-cli --eval ./member.lua nums , 1 2
1) "2"
2) "1"
SCRIPT LOAD script
:将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
:根据给定的 sha1 校验码,执行Lua脚本
EVAL
命令示例:
redis> script load "return 'hello redis'"
"69dd69fc0ba1e25d8e2972008b6baee8eccf7da6"
redis> evalsha 69dd69fc0ba1e25d8e2972008b6baee8eccf7da6 0
"hello redis"
SCRIPT EXISTS script [script ...]
:查看指定的脚本是否已经被保存在缓存当中
SCRIPT FLUSH
:从脚本缓存中移除所有脚本示例:
redis> script load "return 'hello redis'"
"69dd69fc0ba1e25d8e2972008b6baee8eccf7da6"
redis> script exists 69dd69fc0ba1e25d8e2972008b6baee8eccf7da6
1) (integer) 1
redis> script flush
OK
redis> script exists 69dd69fc0ba1e25d8e2972008b6baee8eccf7da6
1) (integer) 0
SCRIPT KILL
:杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效
注:
SCRIPT KILL
执行之后,当前正在运行的脚本会被杀死,执行这个脚本的客户端会从 EVAL 命令的阻塞当中退出,并收到一个错误作为返回值。示例:
客户端A:
# 当前没有正在执行的脚本
redisA> script kill
(error) NOTBUSY No scripts in execution right now.
# 客户端B执行脚本,客户端A杀死运行的脚本
redis> script kill
OK
(0.92s)
客户端B:
# 脚本死循环
redisB> eval "local a = 1; while 1 do a=1; end" 0
# 被杀死后,返回以下信息
(error) ERR Error running script (call to f_c8600a7388e4dd63490c59ede33602dbef5971eb): @user_script:1: Script killed by user with SCRIPT KILL...
(5.00s)
SCRIPT DEBUG YES|SYNC|NO
:使用EVAL可以开启对脚本的调试
注:LDB可以设置成两种模式:同步和异步。
示例:
(1)redis内调试
# 异步调试,回退修改后的数据
redis> script debug yes
OK
# 测试脚本
redis> eval "local a = 1; \n local b = 2; \n return 3" 0
* Stopped at 1, stop reason = step over
-> 1 local a = 1;
# 使用 n 单步调试
redis> n
* Stopped at 2, stop reason = step over
-> 2 local b = 2;
redis> n
* Stopped at 3, stop reason = step over
-> 3 return 3
redis> n
(integer) 3
(Lua debugging session ended -- dataset changes rolled back)
(2)命令行内调试
使用第一节中的示例(3),命令中添加--ldb
进入调试模式:redis-cli --ldb --eval ./member.lua nums , 1 2
--ldb-sync-mode
进入同步模式,此时服务器其他链接被阻塞,调试结束后修改后的数据会被保存调试示例:【参考:http://blog.huangz.me/2017/redis-lua-debuger-introduction.html】
$ redis-cli --ldb --eval ./member.lua nums , 1 2
Lua debugging session started, please use:
quit -- End the session.
restart -- Restart the script in debug mode again.
help -- Show Lua script debugging commands.
* Stopped at 2, stop reason = step over
-> 2 local key = KEYS[1]
lua debugger> n
* Stopped at 5, stop reason = step over
-> 5 local args = ARGV
lua debugger> n
* Stopped at 8, stop reason = step over
-> 8 local result = {}
lua debugger> n
* Stopped at 11, stop reason = step over
-> 11 for m, n in ipairs(args) do
lua debugger> n
* Stopped at 12, stop reason = step over
-> 12 local is_repeat = redis.call("sismember", key, n)
lua debugger> n
<redis> sismember nums 1
<reply> 1
* Stopped at 13, stop reason = step over
-> 13 if (is_repeat) then
lua debugger> n
* Stopped at 14, stop reason = step over
-> 14 table.insert(result, 1, n)
lua debugger> n
* Stopped at 11, stop reason = step over
-> 11 for m, n in ipairs(args) do
lua debugger> n
* Stopped at 12, stop reason = step over
-> 12 local is_repeat = redis.call("sismember", key, n)
lua debugger> n
<redis> sismember nums 2
<reply> 1
* Stopped at 13, stop reason = step over
-> 13 if (is_repeat) then
lua debugger> n
* Stopped at 14, stop reason = step over
-> 14 table.insert(result, 1, n)
lua debugger> n
* Stopped at 11, stop reason = step over
-> 11 for m, n in ipairs(args) do
lua debugger> n
* Stopped at 17, stop reason = step over
-> 17 return result
lua debugger> n
1) "2"
2) "1"
(Lua debugging session ended -- dataset changes rolled back)