七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

石杉的架構筆記發表於2018-12-03

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)

週一至週五早8點半!精品技術文章準時送上!

一、寫在前面

之前寫過一篇文章(《拜託,面試請不要再問我Redis分散式鎖的實現原理》),給大家說了一下Redisson這個開源框架是如何實現Redis分散式鎖原理的,這篇文章再給大家聊一下ZooKeeper實現分散式鎖的原理。

同理,我是直接基於比較常用的Curator這個開源框架,聊一下這個框架對ZooKeeper(以下簡稱zk)分散式鎖的實現。

一般除了大公司是自行封裝分散式鎖框架之外,建議大家用這些開源框架封裝好的分散式鎖實現,這是一個比較快捷省事兒的方式。

二、ZooKeeper分散式鎖機制

接下來我們一起來看看,多客戶端獲取及釋放zk分散式鎖的整個流程及背後的原理。

首先大家看看下面的圖,如果現在有兩個客戶端一起要爭搶zk上的一把分散式鎖,會是個什麼場景?

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

如果大家對zk還不太瞭解的話,建議先自行百度一下,簡單瞭解點基本概念,比如zk有哪些節點型別等等。

參見上圖。zk裡有一把鎖,這個鎖就是zk上的一個節點。然後呢,兩個客戶端都要來獲取這個鎖,具體是怎麼來獲取呢?

我們們就假設客戶端A搶先一步,對zk發起了加分散式鎖的請求,這個加鎖請求是用到了zk中的一個特殊的概念,叫做“臨時順序節點”。

簡單來說,就是直接在"my_lock"這個鎖節點下,建立一個順序節點,這個順序節點有zk內部自行維護的一個節點序號。

比如說,第一個客戶端來搞一個順序節點,zk內部會給起個名字叫做:xxx-000001。然後第二個客戶端來搞一個順序節點,zk可能會起個名字叫做:xxx-000002。大家注意一下,最後一個數字都是依次遞增的,從1開始逐次遞增。zk會維護這個順序。

所以這個時候,假如說客戶端A先發起請求,就會搞出來一個順序節點,大家看下面的圖,Curator框架大概會弄成如下的樣子:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

大家看,客戶端A發起一個加鎖請求,先會在你要加鎖的node下搞一個臨時順序節點,這一大坨長長的名字都是Curator框架自己生成出來的。

然後,那個最後一個數字是"1"。大家注意一下,因為客戶端A是第一個發起請求的,所以給他搞出來的順序節點的序號是"1"。

接著客戶端A建立完一個順序節點。還沒完,他會查一下"my_lock"這個鎖節點下的所有子節點,並且這些子節點是按照序號排序的,這個時候他大概會拿到這麼一個集合:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

接著客戶端A會走一個關鍵性的判斷,就是說:唉!兄弟,這個集合裡,我建立的那個順序節點,是不是排在第一個啊?

如果是的話,那我就可以加鎖了啊!因為明明我就是第一個來建立順序節點的人,所以我就是第一個嘗試加分散式鎖的人啊!

bingo!加鎖成功!大家看下面的圖,再來直觀的感受一下整個過程。

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

接著假如說,客戶端A都加完鎖了,客戶端B過來想要加鎖了,這個時候他會幹一樣的事兒:先是在"my_lock"這個鎖節點下建立一個臨時順序節點,此時名字會變成類似於:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

大家看看下面的圖:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

客戶端B因為是第二個來建立順序節點的,所以zk內部會維護序號為"2"。

接著客戶端B會走加鎖判斷邏輯,查詢"my_lock"鎖節點下的所有子節點,按序號順序排列,此時他看到的類似於:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

同時檢查自己建立的順序節點,是不是集合中的第一個?

明顯不是啊,此時第一個是客戶端A建立的那個順序節點,序號為"01"的那個。所以加鎖失敗

加鎖失敗了以後,客戶端B就會通過ZK的API對他的順序節點的上一個順序節點加一個監聽器。zk天然就可以實現對某個節點的監聽。

如果大家還不知道zk的基本用法,可以百度查閱,非常的簡單。客戶端B的順序節點是:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

他的上一個順序節點,不就是下面這個嗎?

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

即客戶端A建立的那個順序節點!

所以,客戶端B會對:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

這個節點加一個監聽器,監聽這個節點是否被刪除等變化!大家看下面的圖。

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

接著,客戶端A加鎖之後,可能處理了一些程式碼邏輯,然後就會釋放鎖。那麼,釋放鎖是個什麼過程呢?

其實很簡單,就是把自己在zk裡建立的那個順序節點,也就是:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

這個節點給刪除。

刪除了那個節點之後,zk會負責通知監聽這個節點的監聽器,也就是客戶端B之前加的那個監聽器,說:兄弟,你監聽的那個節點被刪除了,有人釋放了鎖。

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

此時客戶端B的監聽器感知到了上一個順序節點被刪除,也就是排在他之前的某個客戶端釋放了鎖。

此時,就會通知客戶端B重新嘗試去獲取鎖,也就是獲取"my_lock"節點下的子節點集合,此時為:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

集合裡此時只有客戶端B建立的唯一的一個順序節點了!

然後呢,客戶端B判斷自己居然是集合中的第一個順序節點,bingo!可以加鎖了!直接完成加鎖,執行後續的業務程式碼即可,執行完了之後再次釋放鎖。

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

三、總結

其實如果有客戶端C、客戶端D等N個客戶端爭搶一個zk分散式鎖,原理都是類似的。

  • 大家都是上來直接建立一個鎖節點下的一個接一個的臨時順序節點
  • 如果自己不是第一個節點,就對自己上一個節點加監聽器
  • 只要上一個節點釋放鎖,自己就排到前面去了,相當於是一個排隊機制。

而且用臨時順序節點的另外一個用意就是,如果某個客戶端建立臨時順序節點之後,不小心自己當機了也沒關係,zk感知到那個客戶端當機,會自動刪除對應的臨時順序節點,相當於自動釋放鎖,或者是自動取消自己的排隊。

最後,我們們來看下用Curator框架進行加鎖和釋放鎖的一個過程:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

其實用開源框架就是這點好,方便。這個Curator框架的zk分散式鎖的加鎖和釋放鎖的實現原理,其實就是上面我們說的那樣子。

但是如果你要手動實現一套那個程式碼的話。還是有點麻煩的,要考慮到各種細節,異常處理等等。所以大家如果考慮用zk分散式鎖,可以參考下本文的思路。

END



如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!


一大波微服務、分散式、高併發、高可用的原創系列文章正在路上

歡迎掃描下方二維碼,持續關注:

七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】

石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授


推薦閱讀:

1、拜託!面試請不要再問我Spring Cloud底層原理

2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?

3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰

4、微服務架構如何保障雙11狂歡下的99.99%高可用

5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理

6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問

7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍

8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!

9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?

10、拜託,面試請不要再問我Redis分散式鎖的實現原理!

11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?

12、億級流量系統架構之如何支撐百億級資料的儲存與計算

13、億級流量系統架構之如何設計高容錯分散式計算系統

14、億級流量系統架構之如何設計承載百億流量的高效能架構

15、億級流量系統架構之如何設計每秒十萬查詢的高併發架構

16、億級流量系統架構之如何設計全鏈路99.99%高可用架構



相關文章