redis的watch命令没有ABA的问题
结论
redis使用watch的时候没有ABA的问题
实验如下图
两个客户端,第一个客户端watch一个key后,第二个客户端修改这个key再恢复到原状,然后第一个客户端执行事务时发现事务失败
原理说明
在每个代表数据库的 redis.h/redisDb 结构类型中, 都保存了一个 watched_keys 字典, 字典的键是这个数据库被监视的键, 而字典的值则是一个链表, 链表中保存了所有监视这个键的客户端。
比如说,以下字典就展示了一个 watched_keys 字典的例子:
其中, 键 key1 正在被 client2 、 client5 和 client1 三个客户端监视, 其他一些键也分别被其他别的客户端监视着。
WATCH 命令的作用, 就是将当前客户端和要监视的键在 watched_keys 中进行关联。
举个例子, 如果当前客户端为 client10086 , 那么当客户端执行 WATCH key1 key2 时, 前面展示的 watched_keys 将被修改成这个样子
通过 watched_keys 字典, 如果程序想检查某个键是否被监视, 那么它只要检查字典中是否存在这个键即可; 如果程序要获取监视某个键的所有客户端, 那么只要取出键的值(一个链表), 然后对链表进行遍历即可
WATCH 的触发
在任何对数据库键空间(key space)进行修改的命令成功执行之后 (比如 FLUSHDB 、 SET 、 DEL 、 LPUSH 、 SADD 、 ZREM ,诸如此类), multi.c/touchWatchedKey 函数都会被调用 —— 它检查数据库的 watched_keys 字典, 看是否有客户端在监视已经被命令修改的键, 如果有的话, 程序将所有监视这个/这些被修改键的客户端的 REDIS_DIRTY_CAS 选项打开:
当客户端发送 EXEC 命令、触发事务执行时, 服务器会对客户端的状态进行检查:
如果客户端的 REDIS_DIRTY_CAS 选项已经被打开,那么说明被客户端监视的键至少有一个已经被修改了,事务的安全性已经被破坏。服务器会放弃执行这个事务,直接向客户端返回空回复,表示事务执行失败。
如果 REDIS_DIRTY_CAS 选项没有被打开,那么说明所有监视键都安全,服务器正式执行事务。
可以用一段伪代码来表示这个检查:
def check_safety_before_execute_trasaction():if client.state & REDIS_DIRTY_CAS:# 安全性已破坏,清除事务状态clear_transaction_state(client)# 清空事务队列clear_transaction_queue(client)# 返回空回复给客户端send_empty_reply(client)else:# 安全性完好,执行事务execute_transaction()
举个例子,假设数据库的 watched_keys
字典如下图所示:
如果某个客户端对 key1 进行了修改(比如执行 DEL key1 ), 那么所有监视 key1 的客户端, 包括 client2 、 client5 和 client1 的 REDIS_DIRTY_CAS 选项都会被打开, 当客户端 client2 、 client5 和 client1 执行 EXEC 的时候, 它们的事务都会以失败告终。
最后,当一个客户端结束它的事务时,无论事务是成功执行,还是失败, watched_keys 字典中和这个客户端相关的资料都会被清除
代码追踪
结构存储如下
watch一个key时,会把那个client加入到这个key的监控列表尾部
修改,删除,重命名,flushDB,swapDB等造成数据修改时,都算是"Touch"了一个key,若这个key是被watch的,则会修改这个key的所有监控client的标记,置为CLIENT_DIRTY_CAS,意思也很明确,就是这个客户端的所有CAS操作都“脏”了,不能再执行了
当服务器收到exec命令时,会先检测这个client是否有CLIENT_DIRTY_CAS标记,若有该标记,就直接返回,不再处理事务
redis的watch命令没有ABA的问题相关推荐
- Redis初学:4(Redis的常用命令)
Redis的常用命令 查看所有key keys * 如下图: 插入key set key value 如下图: 取出key对应的value值 get key 如下图: 查看某个key是否存在 exis ...
- Redis的KEYS命令引起宕机事件
摘要: 使用 Redis 的开发者必看,吸取教训啊! 原文:Redis 的 KEYS 命令引起 RDS 数据库雪崩,RDS 发生两次宕机,造成几百万的资金损失 作者:陈浩翔 Fundebug经授权转载 ...
- redis的flushall命令
redis的flushall命令用来清空redis所有的库,我们平时本地调试redis时都是直接flushall,但到生产环境要注意了,其他的库有可能有生产数据,你要清空redis数据,只能清空你对应 ...
- Redis 键(key) 命令
Redis 键(key) 命令 命令 描述 Redis DEL 命令 该命令用于在 key 存在是删除 key. Redis Dump 命令 序列化给定 key ,并返回被序列化的值. Redis E ...
- redis 基本类型和命令(一)
一.Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). (1) string类型是Redis最基本的数 ...
- Redis 中常用命令
Redis 中常用命令 keys 返回满足给定 pattern 的所有 key. 127.0.0.1:6379> keys *1) "name2"2) "myzse ...
- Redis的超时命令和垃圾回收策略
正如 Java 虚拟机,它提供了自动 GC(垃圾回收)的功能,来保证 Java 程序使用过且不再使用的 Java 对象及时的从内存中释放掉,从而保证内存空间可用. 当程序编写不当或考虑欠缺的时候(比如 ...
- Redis HyperLogLog常用命令
基数并不是存储元素,存储元素消耗内存空间比较大,而是给某一个有重复元素的数据集合(一般是很大的数据集合)评估需要的空间单元数,所以它没有办法进行存储,加上在工作中用得不多,我们要介绍一下 Redis ...
- Redis Config Set 命令
Redis Config Set 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启. 你可以使用它修改配置参数,或者改变 Redis 的持久化(Persistenc ...
最新文章
- 基于的BCH的相关应用是不是该降降温?
- Microsoft Windows 10的LTSC 2019和Version 1809更新简单说明
- Spring AOP通知顺序
- 关掉windows自动更新
- C语言-实现矩阵的转置-随机函数产生随机数并赋予数组中-190222
- 每日两SQL(三),欢迎交流~
- 深入学习consul
- 前端学习(1312):响应报文
- linux mysql 确认命令_LINUX启动/重启/停上MYSQL的命令(详解)
- Java源码混淆,jar包加密,禁止反编译jar包
- SLAM--线性化求解估计位姿
- html ul动态添加li,javaScript动态添加Li元素
- 2048游戏python源代码_python pygame实现2048游戏
- vue3.0+ts+element-plus多页签应用模板:element-plus按需引入与动态换肤
- 第五人格亚服服务器不稳定,【关于第五人格网络问题的部分原因及解决方法】...
- apns 苹果服务器压力,[iOS]APNs推送机制
- 360手机刷机:360N7pro刷机
- 【python】录音语音识别
- python-opencv基础
- python selenium爬取去哪儿网的酒店信息——详细步骤及代码实现
热门文章
- Linux 卷管理详解[ pv vg lv] —— 之三
- myeclipse中代码提示和编辑区颜色设置
- 数据结构的简单理解(2)
- 中石油训练赛 - Flow Finder(树上模拟)
- CodeForces - 1366E Two Arrays(组合数学+思维)
- POJ - 1475 Pushing Boxes(bfs套bfs)
- linux eclipse报错日志,centos6.8命令行启动eclipse报org.eclipse.swt.SWTError错误
- 基于python的搜索引擎论文_技术分享 - 基于python构建搜索引擎系列——(四)检索模型...
- exe软件ui嵌套软件_UI设计行业中的PS软件起什么用途
- bootstrap php zend,Zend Framework教程之Bootstrap类用法概述