zookeeper 分散式鎖的原理及實現

老子是幫主發表於2020-12-05

zookeeper 分散式鎖的原理及實現

本文的分散式鎖原理介紹部分參考了 七張圖徹底講清楚ZooKeeper分散式鎖的實現原理 ,原文已經介紹的非常詳細有趣。我在原文的基礎上,補充實現了實驗部分,算作我的學習筆記,以備後用。

向原作者表示感謝。

zookeeper 分散式鎖原理

為了防止分散式系統中的多個程式之間相互干擾,我們需要一種分散式協調技術來對這些程式進行排程。而這個分散式協調技術的核心就是分散式鎖。

利用 zookeeper 的順序臨時節點,可以很方便地實現分散式鎖和等待佇列。畢竟 zookeeper 設計的初衷,就是為了實現分散式鎖服務的。

如果有客戶端 A 和客戶端 B 爭搶一把分散式鎖,會是一番怎樣的景象?

在這裡插入圖片描述

兩個客戶端的加鎖請求總有個先來後到吧,我們不妨假設客戶端 A 的請求先到達。

zookeeper 接到請求後,會首先建立相應的鎖節點 dir(例如 /zklock),然後在此目錄下為客戶端 A 建立一個 臨時順序節點 ,臨時順序節點是 zookeeper 的 4 種節點型別之一,大概長這樣:
在這裡插入圖片描述
其命名格式一般遵循如下規範: x - { session id } - { 自動遞增編號 }

因為客戶端 A 的請求是第一個到達的,所以分配給 A 的自動遞增編號是一串 0,在此之後的請求,編號會順序遞增。

建立臨時順序節點不等於將鎖分配給了客戶端 A。判別能否獲得鎖的辦法是 客戶端的節點編號是否在 /zklock 路徑下的節點編號佇列中排在隊首 ,因為目前只有客戶端 A 發起了加鎖請求,A 順利獲得鎖。


在這裡插入圖片描述

此時客戶端 B 的加鎖請求到達,zookeeper 同樣會在 /zklock 路徑下為它建立一個臨時順序節點。

由於客戶端 A 的鎖尚未釋放,所以此時 /zklock 路徑下會存在兩個臨時順序節點:
在這裡插入圖片描述
然後客戶端 B 判斷是否可以加鎖,此時發現自己的順序節點並不在隊首,加鎖失敗了。

那就耐心等待吧,等到什麼時候呢,等到排在我前面的那個節點釋放鎖唄。

為了在第一時間獲悉 A 節點的變化情況,B 向 A 節點新增了監聽器。

在這裡插入圖片描述

A 在一頓操作之後,釋放了鎖,同時刪除了自己的臨時順序節點。

這一訊息在第一時間通過監聽器通知到了客戶端 B:你監聽的那個節點已經刪除了,有人釋放了鎖。

在這裡插入圖片描述

於是客戶端 B 再次判斷自己是否滿足加鎖條件:

自己的編號是 01,排在 /zklock 路徑下順序節點佇列隊首,加鎖成功!

在這裡插入圖片描述

zookeeper 分散式鎖實現

我們嘗試基於 zookeeper 實現分散式鎖,實現兩個客戶端 Runner-1 和 Runner-2 的協同工作。以鞏固上述知識點。

效果如下圖,Runner-1 和 Runner-2 會競爭同一個分散式鎖,獲得鎖之後完成各自的工作。

Runner-1 執行完畢釋放鎖之後,會立刻喚醒 Runner-2,而在此之前 Runner-2 只能等待。

Runner-2 執行完畢釋放鎖之後,會立刻喚醒排在它之後的節點,以此類推。

在這裡插入圖片描述
完整程式碼詳見 GitHub

參考文獻

[1] 七張圖徹底講清楚ZooKeeper分散式鎖的實現原理

相關文章