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?選項沒有被打開,那么說明所有監視鍵都安全,服務器正式執行事務。
可以用一段偽代碼來表示這個檢查:
舉個例子,假設數據庫的?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標記,若有該標記,就直接返回,不再處理事務
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的redis的watch命令没有ABA的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hiredis封装事务示例
- 下一篇: linux最大文件句柄数量总结