结论

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的问题相关推荐

  1. Redis初学:4(Redis的常用命令)

    Redis的常用命令 查看所有key keys * 如下图: 插入key set key value 如下图: 取出key对应的value值 get key 如下图: 查看某个key是否存在 exis ...

  2. Redis的KEYS命令引起宕机事件

    摘要: 使用 Redis 的开发者必看,吸取教训啊! 原文:Redis 的 KEYS 命令引起 RDS 数据库雪崩,RDS 发生两次宕机,造成几百万的资金损失 作者:陈浩翔 Fundebug经授权转载 ...

  3. redis的flushall命令

    redis的flushall命令用来清空redis所有的库,我们平时本地调试redis时都是直接flushall,但到生产环境要注意了,其他的库有可能有生产数据,你要清空redis数据,只能清空你对应 ...

  4. Redis 键(key) 命令

    Redis 键(key) 命令 命令 描述 Redis DEL 命令 该命令用于在 key 存在是删除 key. Redis Dump 命令 序列化给定 key ,并返回被序列化的值. Redis E ...

  5. redis 基本类型和命令(一)

    一.Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). (1) string类型是Redis最基本的数 ...

  6. Redis 中常用命令

    Redis 中常用命令 keys 返回满足给定 pattern 的所有 key. 127.0.0.1:6379> keys *1) "name2"2) "myzse ...

  7. Redis的超时命令和垃圾回收策略

    正如 Java 虚拟机,它提供了自动 GC(垃圾回收)的功能,来保证 Java 程序使用过且不再使用的 Java 对象及时的从内存中释放掉,从而保证内存空间可用. 当程序编写不当或考虑欠缺的时候(比如 ...

  8. Redis HyperLogLog常用命令

    基数并不是存储元素,存储元素消耗内存空间比较大,而是给某一个有重复元素的数据集合(一般是很大的数据集合)评估需要的空间单元数,所以它没有办法进行存储,加上在工作中用得不多,我们要介绍一下 Redis ...

  9. Redis Config Set 命令

    Redis Config Set 命令可以动态地调整 Redis 服务器的配置(configuration)而无须重启. 你可以使用它修改配置参数,或者改变 Redis 的持久化(Persistenc ...

最新文章

  1. 基于的BCH的相关应用是不是该降降温?
  2. Microsoft Windows 10的LTSC 2019和Version 1809更新简单说明
  3. Spring AOP通知顺序
  4. 关掉windows自动更新
  5. C语言-实现矩阵的转置-随机函数产生随机数并赋予数组中-190222
  6. 每日两SQL(三),欢迎交流~
  7. 深入学习consul
  8. 前端学习(1312):响应报文
  9. linux mysql 确认命令_LINUX启动/重启/停上MYSQL的命令(详解)
  10. Java源码混淆,jar包加密,禁止反编译jar包
  11. SLAM--线性化求解估计位姿
  12. html ul动态添加li,javaScript动态添加Li元素
  13. 2048游戏python源代码_python pygame实现2048游戏
  14. vue3.0+ts+element-plus多页签应用模板:element-plus按需引入与动态换肤
  15. 第五人格亚服服务器不稳定,【关于第五人格网络问题的部分原因及解决方法】...
  16. apns 苹果服务器压力,[iOS]APNs推送机制
  17. 360手机刷机:360N7pro刷机
  18. 【python】录音语音识别
  19. python-opencv基础
  20. python selenium爬取去哪儿网的酒店信息——详细步骤及代码实现

热门文章

  1. Linux 卷管理详解[ pv vg lv] —— 之三
  2. myeclipse中代码提示和编辑区颜色设置
  3. 数据结构的简单理解(2)
  4. 中石油训练赛 - Flow Finder(树上模拟)
  5. CodeForces - 1366E Two Arrays(组合数学+思维)
  6. POJ - 1475 Pushing Boxes(bfs套bfs)
  7. linux eclipse报错日志,centos6.8命令行启动eclipse报org.eclipse.swt.SWTError错误
  8. 基于python的搜索引擎论文_技术分享 - 基于python构建搜索引擎系列——(四)检索模型...
  9. exe软件ui嵌套软件_UI设计行业中的PS软件起什么用途
  10. bootstrap php zend,Zend Framework教程之Bootstrap类用法概述