基於ZooKeeper的分布式鎖和佇列

2021-08-17 00:23:39 字數 1406 閱讀 3549

完全分布式鎖是全域性同步的,這意味著在任何時刻沒有兩個客戶端會同時認為它們都擁有相同的鎖,使用 zookeeper 可以實現分布式鎖,需要首先定義乙個鎖節點(lock root node)。

需要獲得鎖的客戶端按照以下步驟來獲取鎖:

保證鎖節點(lock root node)這個父根節點的存在,這個節點是每個要獲取lock客戶端共用的,這個節點是persistent的。

第一次需要建立本客戶端要獲取lock的節點,呼叫 create( ),並設定 節點為ephemeral_sequential型別,表示該節點為臨時的和順序的。如果獲取鎖的節點掛掉,則該節點自動失效,可以讓其他節點獲取鎖。

在父鎖節點(lock root node)上呼叫 getchildren( ) ,不需要設定監視標誌。 (為了避免「羊群效應」).

按照fair競爭的原則,將步驟3中的子節點(要獲取鎖的節點)按照節點順序的大小做排序,取出編號最小的乙個節點做為lock的owner,判斷自己的節點id

是否就為owner id,如果是則返回,lock成功。如果不是則呼叫 exists( )監聽比自己小的前一位的id,關注它鎖釋放的操作(也就是exist watch)。

如果第4步監聽exist的watch被觸發,則繼續按4中的原則判斷自己是否能獲取到lock。

釋放鎖:需要釋放鎖的客戶端只需要刪除在第2步中建立的節點即可。

注意事項:

乙個節點的刪除只會導致乙個客戶端被喚醒,因為每個節點只被乙個客戶端watch,這避免了「羊群效應」。

分布式佇列是通用的資料結構,為了在 zookeeper 中實現分布式佇列,首先需要指定乙個 znode 節點作為佇列節點(queue node), 各個分布式客戶端通過呼叫 create() 函式向佇列中放入資料,呼叫create()時節點路徑名帶"qn-"結尾,並設定順序(sequence)節點標誌。 由於設定了節點的順序標誌,新的路徑名具有以下字串模式:"_path-to-queue-node_/qn-x",x 是唯一自增號。需要從佇列中獲取資料/移除資料的客戶端首先呼叫 getchildren() 函式,有資料則獲取(獲取資料後可以刪除也可以不刪),沒有則在佇列節點(queue node)上將 watch 設定為 true,等待觸發並處理最小序號的節點(即從序號最小的節點中取資料)。

實現步驟基本如下:

前提:需要乙個佇列root節點dir

入隊:使用create()建立節點,將共享資料data放在該節點上,節點型別為persistent_sequential,永久順序性的(也可以設定為臨時的,看需求)。

出隊:因為佇列可能為空,2種方式處理:一種如果為空則wait等待,一種返回異常。

等待方式:這裡使用了countdownlatch的等待和watcher的通知機制,使用了treemap的排序獲取節點順序最小的資料(fifo)。

丟擲異常:getchildren()獲取佇列資料時,如果size==0則丟擲異常。

基於ZooKeeper實現分布式鎖

zookeeper 保證了資料的強一致性,zk集群中任意節點 乙個zkserver 上的相同znode下的資料一定是相同的。使用zookeeper可以非常簡單的實現分布式鎖,其基本邏輯如下 客戶端呼叫create 方法建立名為 locknode lock 的節點,需要注意的是,這裡節點的建立型別需要...

基於zookeeper實現分布式鎖

zk有兩種資料節點,一種時持久節點 另一種時瞬時節點,有序,瞬時節點不可再有子節點,會話結束後瞬時節點自動消失 zookeeper的觀察器 可以設定觀察器的三個方法 getdata getchildren exist 資料節點發生變化,傳送給客戶端 觀察器只能監控一次,再監控需要重新設定 zk分布式...

分布式5 zookeeper分布式

一 為什麼需要zookeeper 大部分分布式應用需要乙個主控 協調器或控制器來管理物理分布的子程序 如資源 任務分配等 大部分應用需要開發私有的協調程式,缺乏乙個通用的機制 協調程式的反覆編寫浪費,且難以形成通用 伸縮性好的協調器 zookeeper可以提供通用的分布式鎖服務,用以協調分布式應用,...