Java分布式鎖理論(redis、zookeeper))案例詳解
一、分布式鎖有哪些應用場景?
1、定時任務
2、秒殺搶購,防止庫存超賣的問題
3、雙寫一致性協(xié)議
比如我們?yōu)榱烁呖捎眯源罱朔占?,分別是8080和8081,我們在項目中設立定時任務,目的是每天晚上定時拉取用戶數(shù)據(jù),給每個人發(fā)送一些推薦短信。那么這會出現(xiàn)什么問題呢?8080和8081都有定時任務,到半夜2點同時查詢數(shù)據(jù)庫,同時調用阿里云接口發(fā)短信,那么肯定會重復,使用了分布式鎖,8080搶到鎖執(zhí)行定時任務,那么8081就會阻塞不會執(zhí)行。
那么肯定會有人問,為什么不用synchronized鎖呢?
如果我們是單個項目,用synchronized鎖可以實現(xiàn),但我們用的是集群,synchronized是無法跨jvm的。
二、分布式鎖的實現(xiàn)方案
(1)基于數(shù)據(jù)庫實現(xiàn)——mysql行鎖
(2)基于zookeeper CP模式
(3)基于redis setnx實現(xiàn) AP模式
(4)Redis框架 Redisson、RedisLock
要求:
- 保證一致性:zookeeper 實現(xiàn)分布式鎖
- 保證可用性:redis實現(xiàn)分布式鎖
三、zookeeper實現(xiàn)分布式鎖
zookeeper有個節(jié)點路徑的概念,節(jié)點路徑不能重復,保證了唯一性。

如圖,我有4個springboot項目,首先jvm1先搶到了資源,設置了zk的節(jié)點路徑/lockPath,這個操作就相當于獲取到了鎖,這時其余三個jvm獲取鎖失敗進行阻塞狀態(tài)。當jvm1執(zhí)行任務完畢,調用close()關閉連接,zk自動刪除節(jié)點路徑釋放鎖,zk通知其余3個jvm節(jié)點,它們3個開始競爭鎖。
一直不釋放鎖怎么辦?
我們上面說的是正常理想情況,那么問題來了,如果jvm1一直不釋放鎖,該怎么辦?
可以采用續(xù)命設計(設置超時時間),續(xù)命多次如果業(yè)務還是沒有執(zhí)行完畢的情況下,則認為該鎖超時應該主動釋放該鎖,再將所有業(yè)務代碼回滾,防止其它jvm一直阻塞等待。
如何避免分布式鎖羊群效應問題?

如圖可以看出,當我們有100個jvm的時候,如果jvm1搶到了鎖,執(zhí)行完業(yè)務釋放了鎖,zk就要喚醒其余99個jvm,那喚醒這個操作成本是很高的。
如何解決呢?
采用zk的臨時順序節(jié)點。

我們現(xiàn)在有三個jvm,分別創(chuàng)建了三個臨時順序節(jié)點路徑,誰最小就獲取鎖成功,首先jvm1最小獲取鎖成功,jvm2和jvm3就阻塞,jvm2創(chuàng)建的臨時節(jié)點就去訂閱最小的/lockPath1,當jvm1執(zhí)行完畢釋放鎖并刪除/lockPath1節(jié)點,那么現(xiàn)在/lockPath2就是最小的節(jié)點,獲取鎖成功。
其實就相當于synchronized的公平鎖,jvm1、jvm2、jvm3依次按順序執(zhí)行,這樣我們就不用喚醒所有,jvm1節(jié)點消失,我只需要喚醒jvm2節(jié)點。
四、redis實現(xiàn)分布式鎖
如果不存在值,則返回1,如果存在,則返回0。

那也就是說,我jvm1先setnx返回1搶到了鎖,這時jvm2也setnx發(fā)現(xiàn)返回0,那就無法執(zhí)行業(yè)務。
當我們執(zhí)行業(yè)務完成后,刪除此key就起到了釋放鎖的作用。
那么問題來了,一個老生常談的話題,如果jvm1一直不釋放鎖怎么辦?
答:先拿setnx來爭搶鎖,搶到之后,再用expire命令給鎖加一個過期時間防止鎖忘記了釋放。
但這樣還有問題,如果在setnx之后執(zhí)行expire之前進程意外crash或者要重啟維護了,那該怎么解決?
答:我們可以使用lua腳本來使setnx+expire成為原子操作。
到此這篇關于Java分布式鎖理論(redis、zookeeper) 詳解的文章就介紹到這了,更多相關Java分布式鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺談springboot多模塊(modules)開發(fā)
這篇文章主要介紹了淺談springboot多模塊(modules)開發(fā),詳細的介紹了springboot多模塊的實現(xiàn),有興趣的可以了解一下2017-09-09
SpringBoot 使用hibernate validator校驗
這篇文章主要介紹了SpringBoot 使用hibernate validator校驗,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
SpringBoot?MongoCustomConversions自定義轉換方式
這篇文章主要介紹了SpringBoot?MongoCustomConversions自定義轉換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08

