您好,登錄后才能下訂單哦!
分布式鎖在一組進程之間提供了一種互斥機制。在任何時刻,只有一個進程可以持有鎖。分布式鎖可以應用于大型分布式系統中實現領導者選舉,在任何時間點,持有鎖的進程就是系統的領導者。
為了使用ZooKeeper來實現分布式鎖服務,我們使用順序znode來為那些競爭鎖的進程強制排序。
實現思路很簡單:
首先指定一個作為鎖的znode,通常用它來描述被鎖定的實體,稱為/leader;
然后希望獲得鎖的客戶端創建一些短暫znode,作為鎖znode的子節點。
在任何時間點,順序號最小的客戶端將持有鎖。
例如,兩個客戶端差不多同時創建znode,分別為/leader/lock-1 和 /leader/lock-2,那么創建/leader/lock-1的客戶端將會持有鎖,因為它的znode順序號最小。
ZooKeeper服務是順序的仲裁者,因為它負責分配順序號。
通過刪除znode /leader/lock-1即可簡單的釋放鎖;另外,如果客戶端進程死亡,對應的短暫znode也會被刪除。
接下來,創建/leader/lock-2的客戶端將持有鎖,因為它的順序號緊跟前一個。通過創建一個關于znode刪除的觀察,可以是客戶端在獲得鎖時得到通知。
申請獲取所得偽代碼:
1.在鎖znode下創建一個名為lock-的短暫順序znode,并且記住它的實際路徑名(create操作的返回值)。
2.查詢鎖znode的子節點并設置一個觀察。
3.如果步驟1中所創建的znode在步驟2中所返回的所有子節點中具有最小的順序號,則獲取到鎖。退出。
4.等待步驟2中所設置的觀察的通知并且轉到步驟2.
ZooKeeper中的鎖機制
加鎖:
ZooKeeper 將按照如下方式實現加鎖的操作:
1 ) ZooKeeper 調用 create ()方法來創建一個路徑格式為“ _locknode_/lock- ”的節點,此節點類型為 sequence (連續)和 ephemeral (臨時)。也就是說,創建的節點為臨時節點,并且所有的節點連續編號,即“ lock-i ”的格式。
2 )在創建的鎖節點上調用 getChildren ()方法,來獲取鎖目錄下的最小編號節點,并且不設置 watch 。
3 )步驟 2 中獲取的節點恰好是步驟 1 中客戶端創建的節點,那么此客戶端獲得此種類型的鎖,然后退出操作。
4 )客戶端在鎖目錄上調用 exists ()方法,并且設置 watch 來監視鎖目錄下比自己小一個的連續臨時節點的狀態。
5 )如果監視節點狀態發生變化,則跳轉到第 2 步,繼續進行后續的操作,直到退出鎖競爭。
解鎖:
ZooKeeper 解鎖操作非常簡單,客戶端只需要將加鎖操作步驟 1 中創建的臨時節點刪除即可。
羊群效應
“羊群效應”就是指大量客戶端收到同一事件的通知,但實際只有很少一部分需要處理這一事件。
設想當有成百上千客戶端,都在嘗試獲得鎖,每個客戶端都會在鎖上設置觀察,來捕捉節點的變化。每次鎖被釋放或另一個進程申請獲取鎖時,觀察都會被觸發并且每個客戶端都會收到一個通知,但只有一個客戶端會成功獲得鎖。這時就會造成大量的峰值流量,給zookeeper服務器造成壓力。
為了避免羊群效應,我們需要優化通知事件,將沒必要的觀察通知去掉,如刪除等,只有在前一個順序號的子節點消失時才需要通知下一個客戶端。
ZooKeeper帶有一個Java語言編寫的生產級別的鎖實現,名為writelock,客戶端可以很方便的使用它。
ZooKeeper官網關于鎖服務的介紹:
http://zookeeper.apache.org/doc/trunk/recipes.html#sc_recipes_Locks
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。