Redis从2.6.0版本引入lua脚本的支持,服务器内置lua解释权执行脚本。同时,lua脚本内也可以直接调用redis命令以及是使用lua语言内置的函数库处理命令结果。有了脚本的支持,可以扩展Redis提供的功能外的能力,同时不用修改源码,更加灵活扩展。优点总结:
- 可以使用lua扩展Redis不具备的功能
- lua脚本内支持使用Redis命令,完善
- Redis执行lua脚本是原子性的
- lua脚本可以换成在Redis中,通过校验和调用
1. EVAL 执行脚本
EVAL script numkeys key [key ...] arg [arg ...]
- script 就是脚本内容, Redis内置的是Lua5.1版本的解释器
- numkeys 参数用于指定脚本需要处理的键数量,随后的跟着相同数量的key
- arg 传递给脚本的附加参数,通过ARGV数组访问,索引是从1开始
例子1 返回hello world, 没有参数
EVAL "return 'hello world'" 0
例子2 通过Redis命令来设置数据
EVAL "redis.call('set', KEYS[1], ARGV[1])" 1 "message" "hello"
该脚本的意思是调用Redis的SET命令, 1表示又1个键,那么随后的一个就是键,另外一个就是值,所以KEYS[1]就是message, ARGV[1] 就是hello
2. 值转换
lua执行后的结果可能和Redis执行的值有一些不同,所以会有值转换的规则。
比如,lua脚本返回小数后会转换成Redis的整数
redis> EVAL "return 3.14" 0
(integer) 3
redis> EVAL "return tostring(3.14)" 0
"3.14"
调用者接收值后,在转换成小数即可。
3.缓存和执行脚本
Redis支持SCRIPT LOAD来做脚本缓存,使得下次调用的时候能够直接调用,SCRIPT LOAD缓存脚本后会返回一串SHA1调用和,下次调用的时候通过命令EVALSHA来执行。
语法
缓存脚本,得到sha1值:
SCRIPT LOAD script
通过sha1值执行脚本: 跟EVAL差不多,只是脚本缓存sha1值
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
redis> SCRIPT LOAD "redis.call('set', KEYS[1], ARGV[1]);return redis.call('GET', KEYS[1])"
"e0e1f9fabfc9d4800c877a703b823ac0578ff8db"
redis> EVALSHA "e0e1f9fabfc9d4800c877a703b823ac0578ff8db" 0 "message" "hello world"
"hello world"
4.查看脚本是否已经缓存
SCRIPT EXISTS sha1 [sha1 ...]
5.清空脚本缓存
SCRIPT FLUSH
6.停止正在执行的脚本
SCTRIPT KILL
lua脚本是独占服务器资源的,如果执行过长会影响其他命令的执行。所以
Redis配置选项中有一个lua-time-limit 选项可以设置脚本执行的最长时间。
超过这个时间后,在执行其他命令,就会返回一个busy提示。
这时候通过SCRIPT KILL 命令来停止当前脚本,如果当前lua脚本执行过写命令,那么无法被kill掉,因为违法了原子性的原则,只能等待脚本执行完毕,或者是通过执行SHUTDOWN NOSAVE命令,把redis进程关闭掉,然后再重启redis进程。