Redis WATCH 实现

世界以痛吻我,我仍报之以歌。

简介

WATCH 命令是一个乐观锁,它可以在 EXEC 命令执行之前,监视任意数量的数据库键,并在 EXEC 命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复。

使用WATCH命令监视数据库键

Redis数据库保存着一个watched_keys字典,字典的键是某个被WATCH命令监视的数据库键,字典的值则是一个链表,链表中记录了所有监视相应数据库键的客户端。

通过watched_keys字典,服务器可以清楚地知道哪些数据库键正在被监视,以及哪些客户端正在监视这些数据库键。

监视机制的触发

所有对数据库进行修改的命令,比如 SET、LPUSH、SADD、ZREM、DEL、FLUSHDB 等等,在执行之后都会调用 multi.c/touchWatchKey 函数对 watched_keys 字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有的话,那么 touchWatchKey 函数会将监视被修改键的客户端的 REDIS_DIRTY_CAS 标识打开,表示该客户端的事务安全性已经被破坏。

判断事务是否安全

当服务器接收到一个客户端发来的 EXEC 命令时,服务器会根据这个客户端是否打开了 REDIS_DIRTY_CAS 标识来决定是否执行事务:

  • 如果客户端的 REDIS_DIRTY_CAS 标识已经被打开,那么说明客户端所监视的键当中,至少有一个键已经被修改过了,在这种情况下,客户端提交的事务已经不再安全,所以服务器会拒绝执行客户端提交的事务。
  • 如果客户端的 REDIS_DIRTY_CAS 标识没有被打开,那么说明客户端监视的所有键都没有被修改过(或者客户端没有监视任何键),事务仍然是安全的,服务器将执行客户端提交的这个事务。