Redis之eval+lua实现初步
目录
目录 1
1. 前言 1
2. 执行方式 1
3. 执行过程 3
4. 使用原则 3
1. 前言
Redis的实现保证eval的执行是原子的,即使eval执行的lua超时,Redis也不会自动终止执行。
官方说明如下:
When a script reaches the timeout it is not automatically terminated by Redis since this violates the contract Redis has with the scripting engine to ensure that scripts are atomic. |
2. 执行方式
截止到5.0.5版本,Redis都是将lua解释为一MULTI+EXEC方式执行。当执行以下Redis语句时:
eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 k1 k2 12 ab |
观察它的AOF文件,可以发现内幕:
*1 // 1表示参数个数,包括命令令本身,也就是说命令不带参数 $5 // 第一个参数的字节数,MULTI命令为五个字节 MULTI // Redis命令字 *3 // 表示共三个参数,包括命令字本身 $3 set // Redis命令字 $2 // 为“k1”的字节数 k1 // Redis Key $2 // 为“12”的字节数 12 // Redis Value *3 $3 set // Redis命令字 $2 k2 $2 ab *1 $4 EXEC |
如果lua脚本有语法错误,可能导致部分执行,如执行下述脚本:
eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('incrby',KEYS[2],ARGV[2])" 2 k1 k2 ab 12 |
将得到错误:
ERR Error running script (call to f_de45a142dc8b96e1634403ac2a3f4ccfef4d9dc9): @user_script:1: ERR value is not an integer or out of range |
原因是前一段脚本已将k2的值设置为ab,因此为非整数值,不能对该Key做incrby操作。这个时候AOF将只记录已成功执行部分:
*1 $5 MULTI *3 $3 set $2 k1 $2 ab *1 $4 EXEC |
所以在使用lua之前,一定要先测试好,排除掉语法错误。不然因Redis不支持回滚,会出现中间状态。如果确实需要回滚,也应当在同一段lua中完成提交或回滚。
Redis缓存每一段执行的lua脚本,并且不会主动释放,除非外部调用Redis命令“SCRIPT FLUSH”。Redis对执行的lua脚本做SHA,并用SHA值唯一标识该段lua脚本,后续可直接调用evalsha来执行该脚本,从而避免每次调用传入大段lua脚本。
另外,也可以执行Redis命令“SCRIPT KILL”来主动终止正在执行的lua脚本。但能终止的lua脚本仅限还未执行过写(write)操作,如果被KILL的lua脚本已执行了任意写操作,则“SCRIPT KILL”不能终止它的执行,这样约束的原因是为保证eval命令的原子性,不出现中间结果。
如果仍然要终止已执行写操作的lua脚本,只能通过执行“SHUTDOWN NOSAVE”方式,以阻止中间结果(half-written)的存在。
对于复杂的lua脚本 ,可执行redis-cli并指定参数“--ldb”,即可简单快捷的调试lua脚本。
3. 执行过程
Lua的执行过程如下:
-> 调用lua脚本解释器执行lua脚本 -> lua脚本解释器将lua脚本翻译成redis命令 -> redis状态机中应用lua脚本所执行到的redis命令 -> redis以MULTI+EXEC方式将所执行的redis命令写入到AOF文件 -> 响应客户端执行结果 |
4. 使用原则
使用eval+lua最好遵守以下原则:
1) 执行时间尽可能短,一定要小于连接的超时时长,可使用命令“slowlog get”观察实际情况;
2) 在应用到生产环境之前,测试保证没有语法错误;
3) 不要硬编码Key和Value到脚本中,不然缓存lua脚本的内存越积越多。
Redis之eval+lua实现初步的更多相关文章
- Redis 使用 Eval 多个键值自增操作示例
在PHP上使用Redis 给多个键值进行自增,示例如下: $set['money'] = $this->redis->hIncrByFloat($key, $hour .'_money', ...
- Redis进阶实践之十九 Redis如何使用lua脚本
一.引言 redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...
- Redis基于eval的多字段原子增量计算
目录 目录 1 1. 前言 1 2. 优点 1 3. 方法一:使用struct 2 3.1. 设置初始值(覆盖原有的,如果存在) 2 3.2. 查询k1的值 2 3.3. 设置初始值(覆盖原有的,如果 ...
- 在redis中使用lua脚本
在实际工作过程中,可以使用lua脚本来解决一些需要保证原子性的问题,而且lua脚本可以缓存在redis服务器上,势必会增加性能. 不过lua也会有很多限制,在使用的时候要注意. 在Redis中执行Lu ...
- redis中使用lua脚本
lua脚本 Lua是一个高效的轻量级脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能 使用脚本的好处 1.减少网络开销,在Lua脚 ...
- 新姿势!Redis中调用Lua脚本以实现原子性操作
背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...
- 在redis里面使用lua
Redis从2.6版本开始引入对Lua脚本的支持,通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务端原子的执行多个Redis命令. lua脚本的好处: 减少网络开销.可以将 ...
- Redis中的原子操作(2)-redis中使用Lua脚本保证命令原子性
Redis 如何应对并发访问 使用 Lua 脚本 Redis 中如何使用 Lua 脚本 EVAL EVALSHA SCRIPT 命令 SCRIPT LOAD SCRIPT EXISTS SCRIPT ...
- Springboot与ActiveMQ、Solr、Redis中分布式事物的初步探索
Springboot与ActiveMQ.Solr.Redis中分布式事物的初步探索 解决的场景:事物中的异步问题,当要求数据库与solr服务器的最终一致时. 程序条件: 利用消息队列,当数据库添加成功 ...
随机推荐
- 网络编程中用到的SOCKET是什么?
摘取网络上的一些内容: 什么是TCP/IP.UDP? Socket在哪里呢? Socket是什么呢? 什么是TCP/IP.UDP? TCP/IP(Transmission Control Protoc ...
- C#实现电信短信SMGP协议程序源码
此程序为中国电信SMGP协议程序接口,适合在中国电信申请了短信发送端口的公司使用. 短信群发已经成为现在软件系统.网络营销等必不可少的应用工具.可应用在短信验证.信息群发.游戏虚拟商品购买.事件提醒. ...
- Django ForeignKey不需要参照完整性?
我想在django模型中设置一个ForeignKey字段,它在某些时候指向另一个表.但我希望可以在这个字段中插入一个id,它引用另一个表中可能不存在的条目.因此,如果该行存在于另一个表中,我希望获得F ...
- Java自学-接口与继承 隐藏
Java中的方法隐藏 与重写类似,方法的重写是子类覆盖父类的对象方法 隐藏,就是子类覆盖父类的类方法 步骤 1 : 父类 父类有一个类方法 :battleWin package charactor; ...
- 在ZYNQ上裸机跑ARM程序的演示
今天给大家演示如何在ZYNQ上,裸机跑ARM程序,本测试用的是米尔Z-turn Board单板,测试代码用的XILINX官方的C语言测试程序,用于测试挂接在ARM总线上的设备是否正常,并在串口终端打印 ...
- 时间格式在ios和安卓兼容性的问题:
在做项目时,在时间显示上遇到一个问题,取后台返回的时间时,在ios手机上时间不显示,安卓手机正常,最后通过Vconsole工具发现,ios不能支持用“—”分割的时间,此外后台返回的时间格式为x年x月x ...
- word,excel,ppt转pdf
第一步 需要下载jar包和jacob-1.14.3-x64.dll * <dependency> * <groupId>net.sf.jacob-project</gro ...
- Typora优化-适合不懂CSS代码的小白
转载请注明出处:https://www.cnblogs.com/nreg/p/11116176.html 先来一张优化前与优化后的对比图: 优化前: 优化后: 1.通过 文件-偏好设置 打开主题文件 ...
- RabbitMQ启动出现的问题与解决办法
问题1 使用命令启动 service rabbitmq-server start 报错如下: Starting rabbitmq-server (via systemctl): Job for rab ...
- springboot-发布jar包
其他参考链接: https://www.cnblogs.com/blog5277/p/5920560.html 环境变量配置: 新建系统变量MAVEN_HOME: 在path中添加: ;%MAVEN_ ...