別再糾結(jié)Redis/zookeeper,告訴你分布式鎖的正確解決方案

      網(wǎng)友投稿 861 2025-04-04

      1 秒殺場(chǎng)景下的數(shù)據(jù)一致性問題

      某商品庫(kù)存10,A想買6,B想買5。

      1.1 做夢(mèng)

      A先買走6,庫(kù)存剩4,此時(shí)B應(yīng)該無法購(gòu)買5,給出數(shù)量不足提示

      1.2 現(xiàn)實(shí)

      AB獲取到商品都剩10,A買走6,在A更新庫(kù)存前,B又買走5,此時(shí)B更新庫(kù)存,商品還剩5。

      1.3 想當(dāng)然地解決方案

      給共享資源或?qū)蚕碣Y源的操作加鎖,來保證對(duì)資源的訪問互斥。利用ReentrantLcok或者synchronized即可。

      但是在分布式系統(tǒng)中,由于分布式系統(tǒng)的分布性,這兩種鎖將失去原有鎖的效果。

      必須使用分布式鎖。

      2 分布式鎖的要求

      獲取/釋放鎖的性能好

      獲得鎖必須是原子性的

      網(wǎng)絡(luò)抖動(dòng)或者宕機(jī)等原因?qū)е聼o法釋放鎖時(shí),鎖必須被清除,不然會(huì)發(fā)生死鎖

      可重入

      阻塞鎖和非阻塞鎖,阻塞鎖即沒有獲取到鎖,則繼續(xù)等待獲取鎖;非阻塞鎖即沒有獲取到鎖后,不繼續(xù)等待,直接返回鎖失敗。

      3 分布式鎖實(shí)現(xiàn)方式

      一、數(shù)據(jù)庫(kù)鎖

      基于MySQL鎖表

      完全依靠數(shù)據(jù)庫(kù)唯一索引來實(shí)現(xiàn),當(dāng)想要獲得鎖時(shí),即向數(shù)據(jù)庫(kù)中插入一條記錄,釋放鎖時(shí)就刪除這條記錄

      這種方式存在以下問題:

      鎖沒有失效時(shí)間,解鎖失敗會(huì)導(dǎo)致死鎖,其他線程無法再獲取到鎖,因?yàn)槲ㄒ凰饕齣nsert都會(huì)返回失敗

      只能是非阻塞鎖,insert失敗直接就報(bào)錯(cuò)了,無法進(jìn)入隊(duì)列進(jìn)行重試

      不可重入,同一線程在沒有釋放鎖之前無法再獲取到鎖

      采用樂觀鎖

      增加版本號(hào),根據(jù)版本號(hào)來判斷更新之前有沒有其他線程更新過,如果被更新過,則獲取鎖失敗

      二、緩存鎖

      這里主要是幾種基于redis的

      基于setnx、expire

      基于setnx(set if not exist)的特點(diǎn),當(dāng)緩存里key不存在時(shí),才會(huì)去set,否則直接返回false

      如果返回true則獲取到鎖,否則獲取鎖失敗,為了防止死鎖,我們?cè)儆胑xpire命令對(duì)這個(gè)key設(shè)置一個(gè)超時(shí)時(shí)間來避免。

      但是這里看似完美,實(shí)則有缺陷,當(dāng)我們setnx成功后,線程發(fā)生異常中斷,expire還沒來的及設(shè)置,那么就會(huì)產(chǎn)生死鎖。

      解決上述問題有兩種方案

      采用redis2.6.12版本以后的set,它提供了一系列選項(xiàng)

      EX seconds – 設(shè)置鍵key的過期時(shí)間,單位時(shí)秒

      PX milliseconds – 設(shè)置鍵key的過期時(shí)間,單位時(shí)毫秒

      NX – 只有鍵key不存在的時(shí)候才會(huì)設(shè)置key的值

      XX – 只有鍵key存在的時(shí)候才會(huì)設(shè)置key的值

      第二種采用setnx(),get(),getset()

      (1) 線程Asetnx,值為超時(shí)的時(shí)間戳(t1),如果返回true,獲得鎖。

      (2) 線程B用get 命令獲取t1,與當(dāng)前時(shí)間戳比較,判斷是否超時(shí),沒超時(shí)false,如果已超時(shí)執(zhí)行步驟3

      (3) 計(jì)算新的超時(shí)時(shí)間t2,使用getset命令返回t3(這個(gè)值可能其他線程已經(jīng)修改過),如果t1==t3,獲得鎖,如果t1!=t3說明鎖被其他線程獲取了

      (4) 獲取鎖后,處理完業(yè)務(wù)邏輯,再去判斷鎖是否超時(shí),如果沒超時(shí)刪除鎖,如果已超時(shí),不用處理(防止刪除其他線程的鎖)

      RedLock算法

      zookeeper分布式鎖

      zookeeper是一個(gè)為分布式應(yīng)用提供一致性服務(wù)的軟件,它內(nèi)部是一個(gè)分層的文件系統(tǒng)目錄樹結(jié)構(gòu),規(guī)定統(tǒng)一個(gè)目錄下只能有一個(gè)唯一文件名

      數(shù)據(jù)模型

      永久節(jié)點(diǎn)

      節(jié)點(diǎn)創(chuàng)建后,不會(huì)因?yàn)闀?huì)話失效而消失

      臨時(shí)節(jié)點(diǎn)

      與永久節(jié)點(diǎn)相反,如果客戶端連接失效,則立即刪除節(jié)點(diǎn)

      順序節(jié)點(diǎn)

      與上述兩個(gè)節(jié)點(diǎn)特性類似,如果指定創(chuàng)建這類節(jié)點(diǎn)時(shí),zk會(huì)自動(dòng)在節(jié)點(diǎn)名后加一個(gè)數(shù)字后綴,并且是有序的

      ##監(jiān)視器(watcher):

      當(dāng)創(chuàng)建一個(gè)節(jié)點(diǎn)時(shí),可以注冊(cè)一個(gè)該節(jié)點(diǎn)的監(jiān)視器,當(dāng)節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí),watch被觸發(fā)時(shí),ZooKeeper將會(huì)向客戶端發(fā)送且僅發(fā)送一條通知,因?yàn)閣atch只能被觸發(fā)一次

      別再糾結(jié)Redis/zookeeper,告訴你分布式鎖的正確解決方案

      根據(jù)zookeeper的這些特性來實(shí)現(xiàn)分布式鎖

      創(chuàng)建一個(gè)鎖目錄lock

      希望獲得鎖的線程A就在lock目錄下,創(chuàng)建臨時(shí)順序節(jié)點(diǎn)

      獲取鎖目錄下所有的子節(jié)點(diǎn),然后獲取比自己小的兄弟節(jié)點(diǎn),如果不存在,則說明當(dāng)前線程順序號(hào)最小,獲得鎖

      線程B獲取所有節(jié)點(diǎn),判斷自己不是最小節(jié)點(diǎn),設(shè)置監(jiān)聽(watcher)比自己次小的節(jié)點(diǎn)(只關(guān)注比自己次小的節(jié)點(diǎn)是為了防止發(fā)生“羊群效應(yīng)”)

      線程A處理完,刪除自己的節(jié)點(diǎn),線程B監(jiān)聽到變更事件,判斷自己是最小的節(jié)點(diǎn),獲得鎖。

      小結(jié)

      在分布式系統(tǒng)中,共享資源互斥訪問問題非常普遍,而針對(duì)訪問共享資源的互斥問題,常用的解決方案就是使用分布式鎖,這里只介紹了幾種常用的分布式鎖,分布式鎖的實(shí)現(xiàn)方式還有有很多種,根據(jù)業(yè)務(wù)選擇合適的分布式鎖

      下面對(duì)上述幾種鎖進(jìn)行一下比較:

      數(shù)據(jù)庫(kù)鎖

      優(yōu)點(diǎn):直接使用數(shù)據(jù)庫(kù),使用簡(jiǎn)單。

      缺點(diǎn):分布式系統(tǒng)大多數(shù)瓶頸都在數(shù)據(jù)庫(kù),使用數(shù)據(jù)庫(kù)鎖會(huì)增加數(shù)據(jù)庫(kù)負(fù)擔(dān)。

      緩存鎖

      優(yōu)點(diǎn):性能高,實(shí)現(xiàn)起來較為方便,在允許偶發(fā)的鎖失效情況,不影響系統(tǒng)正常使用,建議采用緩存鎖。

      缺點(diǎn):通過鎖超時(shí)機(jī)制不是十分可靠,當(dāng)線程獲得鎖后,處理時(shí)間過長(zhǎng)導(dǎo)致鎖超時(shí),就失效了鎖的作用。

      zookeeper鎖

      優(yōu)點(diǎn):不依靠超時(shí)時(shí)間釋放鎖;可靠性高;系統(tǒng)要求高可靠性時(shí),建議采用zookeeper鎖。

      缺點(diǎn):性能比不上緩存鎖,因?yàn)橐l繁的創(chuàng)建節(jié)點(diǎn)刪除節(jié)點(diǎn)。

      Redis ZooKeeper 分布式

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:Excel表格如何進(jìn)行排序 Excel表格多種排序方法介紹
      下一篇:一行代碼將SAP CDS view數(shù)據(jù)以ALV的方式輸出
      相關(guān)文章
      亚洲AV香蕉一区区二区三区| 久久综合亚洲鲁鲁五月天| 亚洲国产精品无码专区影院 | 婷婷亚洲天堂影院| 亚洲av成人一区二区三区观看在线| 亚洲国产精品人久久电影| 亚洲美女大bbbbbbbbb| 亚洲高清视频免费| 亚洲最大视频网站| 亚洲国产成人在线视频| 亚洲午夜电影在线观看高清| 亚洲小说区图片区| 91丁香亚洲综合社区| 亚洲午夜无码久久久久软件| 亚洲精品无码成人片久久不卡| 亚洲欧美日韩综合久久久| 亚洲熟妇少妇任你躁在线观看| 亚洲日韩一区二区三区| 亚洲AV香蕉一区区二区三区| 九月婷婷亚洲综合在线| 亚洲性在线看高清h片| 亚洲五月综合缴情在线观看| 亚洲V无码一区二区三区四区观看| 亚洲乱码中文字幕综合| 亚洲AV乱码久久精品蜜桃| 久久久亚洲裙底偷窥综合| 亚洲精品第五页中文字幕| 激情内射亚洲一区二区三区爱妻 | 亚洲中文字幕久久精品无码A| 亚洲色成人四虎在线观看| 久久水蜜桃亚洲AV无码精品| 日韩亚洲国产二区| 久久亚洲精品无码观看不卡| 国产亚洲精品资源在线26u| 亚洲91av视频| 激情综合亚洲色婷婷五月| 久久水蜜桃亚洲AV无码精品| 不卡一卡二卡三亚洲| 久久久久亚洲AV成人无码网站 | 亚洲精品色婷婷在线影院| 国产亚洲AV无码AV男人的天堂|