最近在看redis的lua,看了官网资料和网上一些文章,整理了lua的相关内容,希望对大家有帮助。
0. redis中运行lua的流程的正常流程 1.redis中的lua概要信息 1.1 lua中调用redis命令 1.2 redis数据结构与lua数据结构对应关系 1.3 EVAL和EVALSHA 1.4 脚本缓存 1.5 脚本命令 1.6 其他约定 1.6.1 全局变量保护 1.6.2 Select 使用 1.6.3 redis中lua脚本内置的lib 2.lua的脚本复制 2.1 whole scripts replication(仅脚本复制) 2.2 script effects replication(脚本影响复制Redis 3.2以后支持) 2.3 lua脚本中的可选复制命令 3. redis中lua脚本的debug 3.1 lua脚本中记录日志 3.2 Lua debugger 简要说明( Redis 3.2 提供) 3.2.1 LDB简介 3.2.2 快速入门 4. lua脚本执行超时处理 4.1 设置超时时间 4.2 脚本执行超时后处理方式 5. RedisTemplate调用lua脚本示例 6. 参考资料
在lua脚本中以2种方式调用redis的命令
lua中调用redis的方式 | 对异常处理的方式 |
---|---|
redis.call | 遇到异常将抛出lua error |
redis.pcall | 会将错误信息进行包装,以lua的table类型返回。 |
2个工具函数
redis.error_reply() 返回一个仅包含err元素的table
redis.status_reply()返回一个仅包含ok元素的table
Redis数据结构 | lua数据结构 |
---|---|
integer | number |
bulk | String |
multi bulk | table |
status | lua的table中有一个ok做对应 |
error | lua的table中有一个err做对应 |
Nil bulk, Nil multi bulk | lua的boolean的false |
注意:
举例说明:
redis中2个命令执行lua脚本,EVAL和EVALSHA 。 EVAL 命令要求每次都发送脚本,带宽占用大。 EVALSHA命令为了减少带宽占用,提高效率而出现 EVALSHA 基本与EVAL命令一致,但是第一个参数是lua脚本的sha1值。 如果redis没有该sha1值对应的脚本,会抛出异常。 注意:pipeline中的EVALSHA 需要注意在pipeline中,建议如下:
redis会缓存执行过的脚本,如果1个redis实例执行EVAL命令成功,所有后续的EVALSHA命令也会成功。 lua脚本相对Redis的数据来说,相对较小,可以忽略其内存占用。 SCRIPT FLUSH可以将redis缓存的脚本都移除。 一个持久化的redis和一个持久化的redis的连接,可以保证lua脚本发送过一次后,始终存在于内存中。 后续的EVALSHA执行都会成功。
SCRIPT FLUSH 唯一可以让redis刷新脚本缓存的命令,一般用于云环境或者测试脚本时。 SCRIPT EXISTS sha1 sha2 ... shaN 判断给的的SHA1对应的脚本是否存在,返回一个列表按顺序对应之前的sha1值,列表元素1表示存在,0表示不存在。 SCRIPT LOAD script 向redis服务器注册lua脚本,确保EVALSHA使用正常。 SCRIPT KILL 没有修改数据的情况下,可以用这个命令中断脚本运行。
Redis的lua脚本不允许声明全局变量,防止lua脚本泄漏数据,并保证AOF和同步从服务器能够正确运行, 如果脚本需要维持状态,可以将状态写入redis中。 Lua脚本可以使用2个全局变量KEYS和ARGV,这两个全局变量用于接收传递的KEY和args。
Redis的2.8.12版本后,select命令仅仅影响当前的脚本执行。
base lib table lib string lib. math lib struct lib cjson lib. cmsgpack lib bitop lib redis.sha1hex function. redis.breakpoint redis.debug (用于debug)
redis会将lua脚本复制到从服务器和持久化AOF文件中,因为发送脚本比发送一堆命令更高效。这种模式成为whole scripts replication(仅脚本复制)。 该模式的缺点:
注意: SINTER;SUNION;SDIFF SMEMEBERS;HKEYS;HVALS KEYS 这几个命令具有不确定性因为redis的存储是乱序的,但是redis实现了默认按字典排序,保证每次lua脚本访问一致。
Redis将lua脚本中的对数据的变更记录后,生成MULTI / EXEC 的事务发送到从服务器和AOF文件中。 使用redis.replicate_commands() 进行开启,返回true,表示脚本影响复制开启,否则表示未开启。 使用范围:
该特性不推荐使用,具备一定风险 需要开启script effects replication, redis.set_repl(redis.REPL_ALL) -- AOF和从服务器. redis.set_repl(redis.REPL_AOF) -- 仅AOF. redis.set_repl(redis.REPL_SLAVE) --仅从服务器. redis.set_repl(redis.REPL_NONE) -- 不进行任何复制。
redis.log(loglevel,message)
loglevel 如下:
message仅仅接收String类型
举例:
redis.log(redis.LOG_WARNING,"Something is wrong with this script.")
注意: 请不要再生环境产的Redis上进行lua脚本调试,请使用开发环境的Redis进行调试。注意同步调试(非默认)会阻塞所有的请求,可以使用redis.breakpoint()的方式动态设置断点。
异步调试方式:
./redis-cli --ldb --eval /tmp/script.lua mykey somekey , arg1 arg2
同步模式:
./redis-cli --ldb-sync-mode --eval /tmp/script.lua
会接手如下3个参数
默认情况下是步进模式。
help显示列表如下
调试命令[缩写] | 注释 |
---|---|
[h]elp | 显示这个列表 |
[s]tep | 一步一步的进行调试,步进模式 |
[n]ext | 下一步. |
[c]continue | 跳转到下一个断点 |
[l]list | 显示当前行 |
[l]list [line] | 显示第几行代码.line = 0 显示当前行. |
[l]list [line] [ctx] | 显示当前行,上下指定[ctx]的行数的代码 |
[w]hole | 显示所有代码. |
[p]rint | 打印所有局部变量. |
[p]rint <var> | 打印指定变量,也可打印全局的KEYS和ARGV. |
[b]reak | 显示所有断点. |
[b]reak <line> | 在指定行添加断点. |
[b]reak -<line> | 移除指定行的断点. |
[b]reak 0 | 移除所有断点. |
[t]race | 显示调用栈. |
[e]eval <code> | 执行一些Lua的代码(在不同的调用框架中). |
[r]edis <cmd> | 执行一个redis命令. |
[m]axlen [len] | 设置记录Redis响应与Lua变量dumps 的长度设置为0表示没有限制 |
[a]abort | 停止脚步.同步模式下改变的数据将保留 |
debug示例:
我自己写了一个redislock的lua脚本,仅仅为了进行调试。
1.进入redis的src目录后执行如下语句,这里我们采用默认的调试方式(可以运行的前提是,redis版本3.2+,/usr/luascript中存在lock.lua脚本)
./redis-cli --ldb --eval /usr/luascript/lock.lua
会出现如下图的信息:
2.之后 我们输入whole或w线上脚本的所有语句
这个脚本比较简单就4句话,
3.之后我们在 第一行和第三行加入断点,数据b 1 3,之后入下图所示行号前加入了#号表示有断点
4.之后我们运行到下一个断点,输入c
这里显示参数必须是strings或者integers,实际上是我之前5.调试脚本的时候没有输入参数操作的,没有参数是KEYS和ARGV全局变量的值是nil,所以会报错误。
5. 我们退出调试进程,调试的语句为:
./redis-cli --ldb --eval /usr/luascript/lock.lua WWW , 12 1
注意 ,前后有空格,并重复2,3步后,
6.进行跳转到下一个断点,输入c
7.在这里我们看下KEYS和ARGV的值,输入p KEYS 和p ARGV
8.之后重复按c直到最后一步,会显示运行结果
在redis.conf中设置lua-time-limit 参数来自定义lua脚本的超时时间,单位是毫秒,默认是5000ms,不建议修改改值,目前5s的默认值已经非常大了,理论上一个lua脚本的执行时间应该是毫秒级别的。
当一个脚本超过时间现在,redis不会终止lua脚本,会进行如下操作:
1.先将脚本写入XXX.lua文件中,
2.之后将XXX.lua文件放入src/main/resources/lua中,如下图
RedisTemplate调用execute方法,第一个参数是脚本对象,第二个参数是个列表对应乱脚本中的KEYS,之后的可变参数对应lua脚本中的ARGV。具体操作如下:
@Service
public class LuaService {
@Autowired
StringRedisTemplate template;
public void runLua() throws IOException{
//1,创建默认脚本对象
DefaultRedisScript<Boolean> script=new DefaultRedisScript<Boolean>();
//2.设置默认脚本数据源
ScriptSource scriptSource = new ResourceScriptSource(
new ClassPathResource("/lua/lock1.lua"));
script.setScriptSource(scriptSource);
//3.设置Lua脚本中的KEYS对象
List<String>keys=new ArrayList<String>();
keys.add("WWWW");
template.execute(script, keys, "1200","1");
}
}
https://redis.io/commands/eval 官方关于redis的lua的数据
https://redis.io/topics/ldb 官方关于ldb调试的说明
http://wiki.jikexueyuan.com/project/redis/lua.html 极客学院的lua介绍
http://www.importnew.com/24124.html importnew关于lua的介绍
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有