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服务器的最终一致时. 程序条件: 利用消息队列,当数据库添加成功 ...
随机推荐
- Java学习:迭代器简介
迭代器 java.util.Iterator接口:迭代器(对集合进行遍历) 有两个常用的方法 boolean hasNext() 如果仍有元素可以迭代,则返回 true. 判断集合中还有没有下一个元素 ...
- java学习:循环结构的使用规则和注意事项
循环结构的基本组成部分,一般可分为四部分: 初始化语句:在循环开始最初执行,而且只做唯一一次 条件判断:如果成立,则循环继续:如果不成立,则循环退出. 循环体:重复要做的事情内容,若干行语句. 进步语 ...
- jmeter(二十七)分布式压测注意事项
之前的博客:jemter(二十三):分布式测试简略的介绍了利用jmeter做分布式测试的方法,当时只是介绍了背景和原因,以及基本的配置操作,有同学说写得不够详细. 正好今年双十一,我司的全链路压测,也 ...
- Redis和数据库一致性
1.实时同步 对强一致要求比较高的,应采用实时同步方案,即查询缓存查询不到再从DB查询,保存到缓存: 更新缓存时,先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,直接设置缓存过期 ...
- Java静态变量初始化的坑
class SingleTon { private static SingleTon singleTon = new SingleTon(); public static int count1; pu ...
- org.springframework.stereotype
org.springframework.stereotype 1.@controller 控制器(注入服务) 2.@service 服务(注入dao) 3.@repository dao(实现dao访 ...
- Java NIO , AIO
New IO: 特点:不再阻塞 Channel , Buffer Async IO: 特点:异步
- 百度webuploader如何实现秒传与断点续传
因为这是小众需求,所以默认没有做在webuploader里面,而只是提供hook接口,让用户很简单的扩展此功能. 那么,都有哪些重要的hook接口呢? before-send-file 此hook在文 ...
- AQS原理
1. AQS原理 1.1. 是什么 AQS全程AbstractQueuedSynchronizer抽象队列同步器,它是并发包中的基础类 ReetrantLock,ReentrantReadWriteL ...
- 86.使用webpack爬过的坑
Webpack 4 和单页应用入门 https://github.com/wallstreetcn/webpack-and-spa-guide