快来学习Redis 分布式锁的背后原理
以前在學(xué)校做小項(xiàng)目的時候,用到Redis,基本也只是用來當(dāng)作緩存。可阿粉在工作中發(fā)現(xiàn),Redis在生產(chǎn)中并不只是當(dāng)作緩存這么簡單。在阿粉接觸到的項(xiàng)目中,Redis起到了一個分布式鎖的作用,具體情況是這樣的:該項(xiàng)目在某金融平臺中負(fù)責(zé)某塊業(yè)務(wù),是一個分布式系統(tǒng),線上大概跑著10個左右的實(shí)例。其中有一個步驟需要用戶支付一定的費(fèi)用,Redis分布式鎖在其中大概處于這么一個位置:
可以看到在上分布式鎖之后,系統(tǒng)做了兩個查詢校驗(yàn),然后向數(shù)據(jù)庫中插入了一條訂單記錄,接著才解鎖進(jìn)入支付流程。從業(yè)務(wù)的角度考慮分布式鎖是好理解的,它保證了查詢及插入數(shù)據(jù)整個流程的原子性,防止查詢校驗(yàn)的時候查到臟數(shù)據(jù),使得支付前訂單信息落表的操作串行化執(zhí)行。盡管從業(yè)務(wù)上來說很好理解,但使用Redis作為分布式鎖對我來說是個新知識,阿粉打算結(jié)合項(xiàng)目中的代碼,深挖一下這個知識點(diǎn)。正文1. 為什么要使用分布式鎖在實(shí)際項(xiàng)目中見過分布式鎖后,就不難理解為什么要使用分布式鎖了:總結(jié)來說就是分布式系統(tǒng)要訪問共享資源,為了避免并發(fā)訪問資源帶來錯誤,我們?yōu)楣蚕碣Y源添加一把鎖,讓各個訪問互斥,保證并發(fā)訪問的安全性,這就是使用分布式鎖的原因。2. Redis中分布式鎖的實(shí)現(xiàn)redis中使用分布式鎖很簡單,只要使用setnx指令對某個key上鎖就行:setnx lock test //上鎖 del lock test //解鎖 當(dāng)某個key沒有被占用的時候,setnx指令會返回1,否則返回0,這就是Redis中分布式鎖的使用原理。當(dāng)然我們還可以在上鎖之后使用expire指令給鎖設(shè)置過期時間。看到這里你可能會有疑問,如果我們的程序流程不使用指令解鎖,靠redis設(shè)置時間過期來解鎖,貌似會出問題。假如我們的服務(wù)進(jìn)程在執(zhí)行setnx之后和執(zhí)行expire指令之前掛掉了,那這個鎖豈不是永遠(yuǎn)都不能被釋放?沒錯,這確實(shí)是個問題,當(dāng)時人們在Redis的開源社區(qū)提出了一堆解決方案專門來解決這個問題,可實(shí)現(xiàn)方式都極為復(fù)雜。后來Redis的作者在Redis 2.8版本中加入了set指令的擴(kuò)展參數(shù),使得setnx指令和expire指令能夠同時執(zhí)行,具體使用像下面這個樣子:set lock test ex 5 nx ex:設(shè)置鍵的過期時間 nx:只在鍵不存在時,才對鍵進(jìn)行設(shè)置操作 從此以后,Redis成為了分布式鎖的寵兒。3. 分布式鎖在Redis集群中遇到的麻煩在學(xué)習(xí)了Redis中分布式鎖的使用后,很快我們便發(fā)現(xiàn)了新的問題。在企業(yè)中,Redis基本上都是集群部署的,集群部署避免不了要面對某個節(jié)點(diǎn)宕機(jī)的問題。我們考慮這么一種情況:假設(shè)我們在redis的主節(jié)點(diǎn)上添加了一把分布式鎖,不幸的是主節(jié)點(diǎn)掛掉了,而且主節(jié)點(diǎn)上的鎖還沒有同步到從節(jié)點(diǎn)上,如果此時有客戶端來請求獲得同一把鎖,那么它將順利地獲得鎖,之前那把鎖會被無情地忽視掉,這就是分布式鎖在Redis集群中遇到的麻煩。Redis的作者為了解決這個問題提出了一個叫Redlock的算法,它的原理是這樣的:當(dāng)上鎖的時候,把set指令發(fā)送給過半的節(jié)點(diǎn),只要過半的鎖set成功,就認(rèn)為這次加鎖成功;當(dāng)解鎖的時候,會向所有的節(jié)點(diǎn)發(fā)送del指令。從這個算法的原理可以看出,由于Redlock需要同時對多個節(jié)點(diǎn)進(jìn)行讀寫,因此使用Redlock加分布式鎖的性能要比單機(jī)Redis低很多。因?yàn)橹鲝膹?fù)制出紕漏的概率極低,所以如果對分布式加鎖過程有一定的容錯率的話,可以考慮直接使用set指令;如果追求高可用性,可以考慮使用Redlock算法。當(dāng)然,高可用性的分布式鎖不只有Redis的Redlock,我們還可以用zookeeper或者支持事務(wù)的數(shù)據(jù)庫做分布式鎖。?簡述zookeeper的分布式鎖原理:假設(shè)zk用某個節(jié)點(diǎn)作為分布式鎖,當(dāng)不同的客戶端到zk競爭這把鎖的時候,zk會按順序給不同的客戶端創(chuàng)建一個子節(jié)點(diǎn),掛在作為分布式鎖的節(jié)點(diǎn)下面。假設(shè)第一個來到的客戶端為A,第二個來到的是B,分布式節(jié)點(diǎn)下掛的第一個節(jié)點(diǎn)就是A,B緊跟著A,且B會監(jiān)聽著A的生命狀態(tài),當(dāng)A釋放鎖后A會被刪除,這時B監(jiān)聽到A被刪除,B接能上位獲得分布式鎖了。?在公司的項(xiàng)目中,雖然Redis是以集群的方式部署的,但還是使用最基本的set指令獲取分布式鎖,因?yàn)檫@種方式的性能遠(yuǎn)遠(yuǎn)高于Redlock算法,也高于zk,數(shù)據(jù)庫等分布式鎖實(shí)現(xiàn)方式。雖然在高性能與低概率的錯誤中選擇了高性能,但項(xiàng)目中還是做了其他工作對錯誤情況進(jìn)行兜底的,比如在公司的項(xiàng)目中對主從復(fù)制時的錯誤情況會拋出異常,然后根據(jù)異常會進(jìn)行一些重試的操作。
總結(jié)
這次對Redis分布式鎖的探索算是加深了自己對Redis的理解,但我知道Redis的用處還遠(yuǎn)遠(yuǎn)不止分布式鎖和緩存,留著后面繼續(xù)探索吧。
最后,小編分類整理了許多java進(jìn)階學(xué)習(xí)材料和BAT面試給熱愛IT行業(yè)的你,如果需要資料的請轉(zhuǎn)發(fā)此文章后再私聊小編回復(fù)【java】就能領(lǐng)取2019年java進(jìn)階學(xué)習(xí)資料和BAT面試題以及《Effective Java》(第3版)電子版書籍。也可以加群:712263501領(lǐng)取海量學(xué)習(xí)資料進(jìn)行學(xué)習(xí)。
總結(jié)
以上是生活随笔為你收集整理的快来学习Redis 分布式锁的背后原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 归零者怎么打
- 下一篇: 国内 Java 开发者必备的两个神器:M