Redis CAS樂觀鎖實現
隨著業務量的增大,系統必然遇到了併發資源搶佔的問題,也就引發了分散式鎖的討論。在實現了ZK鎖後,雖然解決了部分問題,但總感覺還有更好的方法(Redis鎖效能肯定是比ZK高的,在這裡就不討論了)。所以藉助於CAS理論和Redis實現無鎖併發的念想就慢慢滋生了。順便讀了下Redis官方文件和Redis設計與實現發現Redis已經實現了CAS的操作,也就是我們所說的偽事物。
現狀
先說下目前業務現狀,目前有個動態派工師傅資源搶佔的問題。目前使用的是ZK鎖加資料庫操作,凸顯的問題就是業務漏斗式篩選時間過長,導致資料庫鎖等待增多。在高併發下這簡直就是致命的問題。
優化方案
1、將師傅資料從目前的資料庫操作轉移到Redis快取操作,目的減少資料庫壓力,解決鎖等待資源佔用問題。
2、使用樂觀鎖替代目前的ZK鎖,提高單體併發能力。
實現方案
樂觀鎖實現使用Redis 自有的watch multi exec等命令進行封裝
總體就是一句話概括,使用了相關命令就實現了CAS操作
下面詳細介紹下Redis的CAS方案
說起Redis的CAS就必須要說到它的事物了
Redis事物
Redis 通過MULTI 、EXEC、WATCH等命令來實現事物功能。事物提供了一種將多個命令請求打包,然後一次性、按順序的執行多個命令的機制,並且在事物執行期間,伺服器不會中斷事物而去執行其他客戶端的命令請求,它會將事物中所有的命令都執行完畢。Redis事物不支援回滾操作,所以事物佇列中某個命令執行錯誤,整個事物也會繼續執行下去。
事物階段
- 開始事物
MULTI 代表將客戶端的REDIS__MULTI選項開啟,使客戶端進入事物狀態執行命令返回QUEUED 代表命令已經進入事物佇列了,EXEC命令將這個事物提交給伺服器執行.
- 命令入隊
當Redis處理一個請求時, 其實並不是所有的命令都會被放進事務佇列, 其中的例外就是 EXEC 、 DISCARD 、 MULTI 和 WATCH 這四個命令 。當這四個命令從客戶端傳送到伺服器 時, 它們會像客戶端處於非事務狀態一樣, 直接被伺服器執行。每個Redis客戶端都有自己的事物狀態,這個事物狀態儲存在客戶端狀態的mstate屬性裡面。
- 提交事務
一個處於事物狀態的客戶端向伺服器傳送EXEC命令時,這個EXEC命令將立即被伺服器執行。伺服器會遍歷這個客戶端的事物佇列,執行佇列儲存的所有命令,最後統一返回所有的執行結果。 執行是有序的按照先進先出(FIFO)的順序執行機制。事務在執行過程中不會被中斷,所有命令命令執行之後,事務才結束。
WATCH命令實現
WATCH命令就是一個樂觀鎖,它可以在EXEC命令執行之前,監視任意數量的資料庫鍵,並在EXEC命令執行時,檢查被監視的鍵是否被修改了,如果被修改了伺服器將拒絕執行事物,並向客戶端返回空。
通過此圖會發現事物期間,其他客戶端如果執行了相同的key操作,將會被忽略
T4時間客戶端二修改了testkey值,當T6階段客戶端一執行EXEC命令時,伺服器會發現WATCH的鍵已經被修改,因此伺服器拒絕執行客戶端A的事物,並返回空。
WATCH監控
每個Redis資料庫都儲存著一個watched_keys字典來儲存被監控的健,字典值是一個連結串列,連結串列中記錄了所有監視相應鍵的客戶端
監控機制觸發
所有對資料庫進行修改的命令,如SET、LPUSH、SADD、ZREM、DEL、FLUSHDB等,在執行之後都會呼叫multi.c/touchWatchKey函式對watched_keys字典進行檢查,檢視是否有客戶端正在監視剛剛被命令修改過的key,有的話touchWatchKey函式會將監視的客戶端的REDIS_DIRTY_CAS標識開啟,表示該客戶端事物安全性已經被破壞。
判斷事物是否安全
當伺服器接收到一個客戶端發來的EXEC命令時,伺服器將會根據這個客戶端是否開啟REDIS_DIRTY_CAS標識來決定是否執行事物
總結
- 事物提供了一種將多個命令打包,然後一次性有序(FIFO)執行的機制
- 事物執行過程不會被中斷
- 帶WATCH命令的事物會將客戶端和被監視的鍵在資料庫watched_keys字典中進行關聯,當鍵被修改程式會將所有監視鍵的客戶端REDIS_DIRTY_CAS標識開啟
- 在客戶端提交EXEC命令時,會檢查REDIS_DIRTY_CAS標識,標識開啟事物將不會被執行
- Redis事物具有ACID的特性(當伺服器執行在AOF模式下,並且appendfsync選項值為always時才具有永續性
相關文章
- 樂觀鎖CAS
- 深入分析CAS(樂觀鎖)
- 【mybatis-plus】什麼是樂觀鎖?如何實現“樂觀鎖”MyBatis
- Redis的事務、樂觀鎖和悲觀鎖Redis
- Java 中的悲觀鎖和樂觀鎖的實現Java
- 悲觀鎖與樂觀鎖的實現(詳情圖解)圖解
- 樂觀鎖和悲觀鎖策略的區別與實現
- 利用MySQL中的樂觀鎖和悲觀鎖實現分散式鎖MySql分散式
- 使用ORA_ROWSCN實現樂觀鎖定
- 悲觀鎖和樂觀鎖
- laravel樂觀鎖和悲觀鎖Laravel
- mysql悲觀鎖以樂觀鎖MySql
- MySQL鎖(樂觀鎖、悲觀鎖、多粒度鎖)MySql
- MySQL 樂觀鎖MySql
- java-樂觀鎖與悲觀鎖Java
- MybatisPlus - [03] 樂觀鎖&悲觀鎖MyBatis
- 關於庫存超賣問題,悲觀鎖和樂觀鎖的不同實現
- 死磕java concurrent包系列(一)從樂觀鎖、悲觀鎖到AtomicInteger的CAS演算法Java演算法
- [轉帖]SQL Server 鎖機制 悲觀鎖 樂觀鎖 實測解析SQLServer
- 關於樂觀鎖與悲觀鎖的實際應用
- SSM (十五) 樂觀鎖與悲觀鎖的實際應用SSM
- MySQL樂觀鎖和悲觀鎖介紹MySql
- Java中的鎖之樂觀鎖與悲觀鎖Java
- 面試必備之悲觀鎖與樂觀鎖面試
- MySQL 悲觀鎖與樂觀鎖的詳解MySql
- 面試必備之樂觀鎖與悲觀鎖面試
- Java彌散系列 - 樂觀鎖與悲觀鎖Java
- SQLServer樂觀鎖定和悲觀鎖定例項SQLServer
- Spring Boot2+JPA之悲觀鎖和樂觀鎖實戰Spring Boot
- Java鎖?分散式鎖?樂觀鎖?行鎖?Java分散式
- 【鎖機制】共享鎖、排它鎖、悲觀鎖、樂觀鎖、死鎖等等
- Java併發:樂觀鎖Java
- 樂觀鎖與悲觀鎖及應用舉例
- 資料庫中的悲觀鎖和樂觀鎖資料庫
- JPA和Hibernate的樂觀鎖與悲觀鎖
- Redis樂觀鎖在電影購票業務中的應用Redis
- 深入理解Redis事務、事務異常、樂觀鎖、管道Redis
- Java中的樂觀鎖——無鎖策略Java