Lua脚本是一种轻量级脚本,采用C语言编写
为什么使用Lua脚本
- 批量执行命令,减少网络开销
- 原子性,redis会将Lua脚本中的命令当做一个整体来执行,不会被其他的请求打断
- 操作集合的复用,或者复杂命令的复用
redis中执行lua脚本
redis> eval lua-script key-num [key1 key2 key3 ...] [value1 value2 value3 ...]
- eval代表执行Lua语言的命令
- lua-script代表Lua语言脚本内容
- key-num 表示参数中有多少个key,需要注意的是Redis中key是从1开始的,如果没有key的参数,那么写0
- [key1 key2 key3 ...]是key作为参数传递给Lua语言,也可以不填,但是需要和key-num的个数对应起来
- [value1 value2 value3 ...]这些参数传递给Lua语言,它们是可填可不填的
127.0.0.1:6379> eval "return 'hello word'" 0
"hello word"
在Lua脚本中执行redis命令
redis.call(command,key [param1,param2...])
- command是命令,包括set、get、del等
- key是被操作的键
- param1,param2...代表给key的参数
127.0.0.1:6379> eval "redis.call('set',KEYS[1],ARGV[1])" 1 qs 2673
(nil)
127.0.0.1:6379> get qs
"2673"
Lua脚本文件
redis-cli --eval qs.lua 0
redis.call('set','qs','lua666')
return redis.call('get','qs')
案例
对IP进行限流
在x秒内只能访问y次
key:ip
value:记录访问次数
-- 对传进来的keys[1]进行递增,如果不存在就set一个,值为1
local num = redis.call('incr',KEYS[1])
-- 如果是第一次访问
if tonumber(num)==1 then
-- 设置过期时间,单位秒
redis.call('expire',KEYS[1],ARGV[1])
return 1
-- 判断是否超过访问限制次数
elseif tonumber(num)>tonumber(ARGV[2]) then
return 0
else
return 1
end
./redis-cli --eval "ip_limit.lua" app:ip:limit:192.168.0.8.111 , 10 5
keys和argv中间用逗号隔开,逗号前后都有空格
缓存Lua脚本
如果lua脚本文件较大的话,每次客户端请求都会造成比较大的网络开销,所以将lua脚本缓存在服务端,生成lua脚本的摘要,通过摘要直接调用lua脚本
执行script load "return 'hello word'"
会生成一个sha1的摘要
执行的时候执行 evalsha 命令
127.0.0.1:6379> script load "return 'hello word'"
"2d7cc5c7eb8fb4d83cf3c9a1a2f0462143f169f6"
127.0.0.1:6379> evalsha 2d7cc5c7eb8fb4d83cf3c9a1a2f0462143f169f6 0
"hello word"
127.0.0.1:6379>
缓存大脚本时,每行命令用分号;
隔开,写成1行
脚本超时
执行SCRIPT KILL
或者SHUTDOWN NOSAVE
可以结束正在进行的脚本
如果lua脚本中没有进行值的修改,执行SCRIPT KILL
即可,否则执行SHUTDOWN NOSAVE
关闭客户端