(轉載)Zookeeper實現分佈式鎖

原文鏈接:https://www.jianshu.com/p/3f407b37c34f

本文轉載於簡書,是自己在上班之餘的學習記錄。怕將來用到找不到。特此轉載!

原文地址:https://www.jianshu.com/p/3f407b37c34f

 

 

ZooKeeper 節點是有生命週期的,這取決於節點的類型。在 ZooKeeper 中,節點類型可以分爲持久節點(PERSISTENT )、臨時節點(EPHEMERAL),以及時序節點(SEQUENTIAL ),具體在節點創建過程中,一般是組合使用,可以生成以下 4 種節點類型。

一、持久節點(PERSISTENT)

所謂持久節點,是指在節點創建後,就一直存在,直到有刪除操作來主動清除這個節點——不會因爲創建該節點的客戶端會話失效而消失。

二、持久順序節點(PERSISTENT_SEQUENTIAL)

這類節點的基本特性和上面的節點類型是一致的。額外的特性是,在ZK中,每個父節點會爲他的第一級子節點維護一份時序,會記錄每個子節點創建的先後順序。基於這個特性,在創建子節點的時候,可以設置這個屬性,那麼在創建節點過程中,ZK會自動爲給定節點名加上一個數字後綴,作爲新的節點名。這個數字後綴的範圍是整型的最大值。

三、臨時節點(EPHEMERAL)

和持久節點不同的是,臨時節點的生命週期和客戶端會話綁定。也就是說,如果客戶端會話失效,那麼這個節點就會自動被清除掉。注意,這裏提到的是會話失效,而非連接斷開。另外,在臨時節點下面不能創建子節點。

四、臨時順序節點(EPHEMERAL_SEQUENTIAL)

 可以用來實現分佈式鎖

當很多進程需要訪問共享資源時,我們可以通過zk來實現分佈式鎖。主要步驟是:

1.建立一個節點,假如名爲:lock 。節點類型爲持久節點(PERSISTENT)

2.每當進程需要訪問共享資源時,會調用分佈式鎖的lock()或tryLock()方法獲得鎖,這個時候會在第一步創建的lock節點下建立相應的順序子節點,節點類型爲臨時順序節點(EPHEMERAL_SEQUENTIAL),通過組成特定的名字name+lock+順序號。

3.在建立子節點後,對lock下面的所有以name開頭的子節點進行排序,判斷剛剛建立的子節點順序號是否是最小的節點,假如是最小節點,則獲得該鎖對資源進行訪問。

4.假如不是該節點,就獲得該節點的上一順序節點,並給該節點是否存在註冊監聽事件。同時在這裏阻塞。等待監聽事件的發生,獲得鎖控制權。

5.當調用完共享資源後,調用unlock()方法,關閉zk,進而可以引發監聽事件,釋放該鎖。

實現的分佈式鎖是嚴格的按照順序訪問的併發鎖。

 

一、分佈式鎖介紹

        分佈式鎖主要用於在分佈式環境中保護跨進程、跨主機、跨網絡的共享資源實現互斥訪問,以達到保證數據的一致性。

二、架構介紹

在介紹使用Zookeeper實現分佈式鎖之前,首先看當前的系統架構圖

解釋: 左邊的整個區域表示一個Zookeeper集羣,locker是Zookeeper的一個持久節點,node_1、node_2、node_3是locker這個持久節點下面的臨時順序節點。client_1、client_2、client_n表示多個客戶端,Service表示需要互斥訪問的共享資源。

三、分佈式鎖獲取思路

 

        1.獲取分佈式鎖的總體思路

        在獲取分佈式鎖的時候在locker節點下創建臨時順序節點,釋放鎖的時候刪除該臨時節點。客戶端調用createNode方法在locker下創建臨時順序節點,

然後調用getChildren(“locker”)來獲取locker下面的所有子節點,注意此時不用設置任何Watcher。客戶端獲取到所有的子節點path之後,如果發現自己在之

前創建的子節點序號最小,那麼就認爲該客戶端獲取到了鎖。如果發現自己創建的節點並非locker所有子節點中最小的,說明自己還沒有獲取到鎖,

此時客戶端需要找到比自己小的那個節點,然後對其調用exist()方法,同時對其註冊事件監聽器。之後,讓這個被關注的節點刪除,則客戶端的Watcher會

收到相應通知,此時再次判斷自己創建的節點是否是locker子節點中序號最小的,如皋是則獲取到了鎖,如果不是則重複以上步驟繼續獲取到比自己小的一個

節點並註冊監聽。當前這個過程中還需要許多的邏輯判斷。

 

2.獲取分佈式鎖的核心算法流程

        下面同個一個流程圖來分析獲取分佈式鎖的完整算法,如下:

解釋:客戶端A要獲取分佈式鎖的時候首先到locker下創建一個臨時順序節點(node_n),然後立即獲取locker下的所有(一級)子節點。

此時因爲會有多個客戶端同一時間爭取鎖,因此locker下的子節點數量就會大於1。對於順序節點,特點是節點名稱後面自動有一個數字編號,

先創建的節點數字編號小於後創建的,因此可以將子節點按照節點名稱後綴的數字順序從小到大排序,這樣排在第一位的就是最先創建的順序節點,

此時它就代表了最先爭取到鎖的客戶端!此時判斷最小的這個節點是否爲客戶端A之前創建出來的node_n,如果是則表示客戶端A獲取到了鎖,

如果不是則表示鎖已經被其它客戶端獲取,因此客戶端A要等待它釋放鎖,也就是等待獲取到鎖的那個客戶端B把自己創建的那個節點刪除。

此時就通過監聽比node_n次小的那個順序節點的刪除事件來知道客戶端B是否已經釋放了鎖,如果是,此時客戶端A再次獲取locker下的所有子節點,

再次與自己創建的node_n節點對比,直到自己創建的node_n是locker的所有子節點中順序號最小的,此時表示客戶端A獲取到了鎖!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章