目錄
Zookeeper是如何實現分布式鎖的
標簽 : Zookeeper 分布式
實現分布式鎖要考慮的重要問題
1. 三個核心要素
加鎖, 解鎖, 鎖超時
2. 三個問題
- 要保證原子性操作, 加鎖和鎖超時的操作要一次性執行完畢
- 防止誤刪鎖
- 在誤刪的基礎上, 加一個守護線程, 為鎖續命.
什么是臨時順序節點
Zookeeper的數據存儲結構就像是一棵樹, 這棵樹由節點組成, 這種節點叫做Znode. Znode分為四種類型.
1. 持久節點(Persistent)
默認的節點類型, 創建節點的客戶端和Zookeeper斷開連接之后, 該節點依舊存在.
2. 持久順序節點(Persistent Sequential)
所謂順序節點, 就是在創建節點的時候, Zookeeper根據節點的創建時間順序給節點的名稱進行編號.
3. 臨時節點(Ephemeral)
和持久節點相反, 當創建節點的客戶端與Zookeeper斷開連接之后,臨時節點會被刪除.
4. 臨時順序節點(Ephemeral Sequential)
在創建節點時, Zookeeper根據創建的時間順序給該節點名稱進行編號; 當創建節點的客戶端與Zookeeper斷開連接之后,臨時節點會被刪除.
Zookeeper實現分布式鎖的原理
上面已經說了Znode的四種類型, 其中最后一種類型 臨時順序節點 是最有利於實現Zookeeper分布式鎖的.
1. 獲取鎖
- 首先, 在Zookeeper當中創建一個持久節點ParentLock. 當第一個客戶端想要獲得操作某項數據的鎖的時候,需要在該持久節點之下簡歷一個臨時順序節點
Lock1
.
- 之后,
客戶端1
查找ParentLock
下面所有的臨時順序節點並按照大小排序, 判斷自己所創建的節點Lock1
是不是順序最靠前的一個. 如果是第一個節點,則成功獲得鎖.
- 此時,
客戶端2
前來獲取該項數據的鎖, 則在ParentLock
下再創建一個臨時順序節點Lock2
.
客戶端2
查找ParentLock下面所有的臨時順序節點並排序,發現自己的Lock2
節點並不是最靠前的. 於是客戶端2
向排序僅僅比它靠前的Lock1
注冊Watcher
, 用於監聽Lock1
動態. 這意味着Lock2
搶鎖失敗, 進入等待狀態.
- 此時, 如果有一個
客戶端3
前來獲取鎖, 則在ParentLock
下在創建一個臨時順序節點Lock3
.
客戶端3
查找ParentLock
下面所有的臨時順序節點並排序, 判斷自己所創建的節點Lock3
是不是順序最靠前的一個, 結果發現Lock3
不是最靠前的. 於是客戶端3
同樣搶鎖失敗, 進入了等待狀態.
- 這個時候
客戶端1
得到了鎖,客戶端2
監聽了客戶端1
,客戶端3
監聽了客戶端2
. 這樣剛好形成一個等待的隊列.
2. 釋放鎖
釋放鎖有兩種情況
2.1 任務完成, 客戶端顯示釋放
- 當任務完成時,
客戶端1
會顯示的調用刪除節點Lock1
的指令.
2.2 任務執行過程中, 客戶端崩潰
- 獲得鎖的
客戶端1
在執行任務的過程中, 如果崩潰, 則會斷開和Zookeeper
服務器的鏈接, 根據臨時節點的特性, 相關聯的Lock1
會隨之自動刪除.
3. 獲得鎖
- 由於
客戶端2
一直在監聽Lock1
的狀態,這個時候發現Lock1
注銷了,客戶端2
會立即接收到通知. 這個時候客戶端2
會再次查詢ParentLock
下的所有節點, 確認自己所創建的節點是不是最小的節點, 如果是最小的則成功獲得鎖.
同理可推至
客戶端3
總結
Zookeeper和Redis分布式鎖的比較
分布式鎖 | 優點 | 缺點 |
---|---|---|
Zookeeper | 1.有封裝好的框架,容易實現. 2.有等待鎖的機制( Watcher ),可以提高搶鎖的效率,好處多多 |
添加和刪除節點的性能比較低 |
Redis | Set 和Del 的性能比較高(畢竟鍵值數據庫,Hash) |
1.實現復雜,需要考慮原子性,誤刪等情況. 2.沒有等待鎖的機制,只能通過客戶端的自旋來等鎖,效率低下. |
9: https://www.funtl.com/assets/Lusifer2018101900098]: https://www.funtl.com/assets/Lusifer201810190008.png