Redis使用lua脚本

young 496 2021-10-18

Lua脚本是一种轻量级脚本,采用C语言编写

为什么使用Lua脚本

  1. 批量执行命令,减少网络开销
  2. 原子性,redis会将Lua脚本中的命令当做一个整体来执行,不会被其他的请求打断
  3. 操作集合的复用,或者复杂命令的复用

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关闭客户端