zookeeper的節點有四種節點:node
Non-sequence節點,多個客戶端同時建立同一 Non-sequence節點時,只有一個可建立成功,其它勻失敗。而且建立出的節點名稱與建立時指定的節點名徹底同樣服務器
此外,zookeeper有watch機制,能夠監聽到數據的變化從而觸發watch,watch有如下特色:架構
主動推送 Watch被觸發時,由 Zookeeper 服務器主動將更新推送給客戶端,而不須要客戶端輪詢。分佈式
一次性 數據變化時,Watch 只會被觸發一次。若是客戶端想獲得後續更新的通知,必需要在 Watch 被觸發後從新註冊一個Watch。性能
可見性 若是一個客戶端在讀請求中附帶 Watch,Watch 被觸發的同時再次讀取數據,客戶端在獲得 Watch消息以前確定不可能看到更新後的數據。換句話說,更新通知先於更新結果。spa
順序性 若是多個更新觸發了多個 Watch ,那 Watch 被觸發的順序與更新順序一致。線程
基於zookeeper的分佈式鎖有兩種實現方式:公平模式和非公平模式,能夠利用zookeeper的節點的這幾種特性來實現不一樣的分佈式鎖code
競爭鎖:進程
非公平模式的zookeeper的分佈式鎖使用的是Non-sequence+Ephemeral節點實現的,此節點的實現方式和Redis實現分佈式鎖的實現方式比較相似.
zookeeper因爲Non-sequence節點的特性,在建立節點時,多個節點只會建立一個成功,這個節點就是主節點,其他的節點就是follower,這樣就保證了只有一個線程可以拿到鎖圖片
釋放鎖:
因爲Ephemeral節點的存在,鎖的得到者應該可以正確釋放已經得到的鎖,而且當得到鎖的進程宕機時,鎖應該自動釋放,從而使得其它競爭方能夠得到該鎖,從而避免出現死鎖的狀態
或者leader主動釋放鎖,而且當領導所在進程宕機時,領導權應該自動釋放,從而使得其它參與者可從新競爭領導而避免進入無主狀態
感知鎖的釋放:
感知鎖的釋放主要是watch機制的存在,在leader釋放鎖時,節點刪除,其餘線程會感知到鎖的釋放,從而競爭鎖
總結:
非公平模式實現簡單,每一輪選舉方法都徹底同樣 競爭參與方很少的狀況下,效率高。每一個 Follower 經過 Watch 感知到節點被刪除的時間不徹底同樣,只要有一個 Follower 獲得通知即發起競選,便可保證當時有新的 Leader 被選出 給Zookeeper 集羣形成的負載大,所以擴展性差。若是有上萬個客戶端都參與競選,意味着同時會有上萬個寫請求發送給 Zookeper。如《Zookeeper架構》一文所述,Zookeeper 存在單點寫的問題,寫性能不高。同時一旦 Leader 放棄領導權,Zookeeper 須要同時通知上萬個 Follower,負載較大。
競爭鎖:
公平鎖主要依據的是zookeeper的Sequence+Ephemeral節點的特性實現的 在線程啓動時會根據線程進行編號,因爲Sequence節點的特性,每一個線程均能成功建立出節點,此處節點的選舉有些相似於zookeeper的選舉,在啓動時會根據節點的編號順序來指定主節點,例若有三個節點,編號分別爲1,2,3,此時會指定最小的節點爲leader,其他的節點爲follower,同時此節點對應的線程watch是比本身節點小的節點,也就是說3線程watch2節點,2線程watch1節點
釋放鎖:
Leader 若是主動放棄領導權,直接刪除其建立的節點便可. 若是 Leader 所在進程意外宕機,其與 Zookeeper 間的 Session 結束,因爲其建立的節點爲Ephemeral類型,故該節點自動被刪除.
感知鎖的釋放:
與非公平模式不一樣,每一個 Follower 並不是都 Watch 由 Leader 建立出來的節點,而是 Watch 序號恰好比本身序號小的節點,因此主節點釋放後恰好比主節點序號大的節點就會感知到,好比:1節點釋放後2線程會watch到1節點釋放鎖從而競爭鎖,可是在競爭鎖以前會判斷此節點是不是最小的節點,若是不是仍然不會成爲主節點.(1節點釋放鎖以前2節點宕機的狀況下,3線程會watch到2節點的釋放,此時3線程會判斷3節點是不是最小的節點,因爲此時1節點沒有刪除,因此3節點不會成爲leader,而且3線程會watch比2節點小的節點也就是1節點)
總結:
實現相對複雜 擴展性好,每一個客戶端都只 Watch 一個節點且每次節點被刪除只須通知一個客戶端 舊 Leader 放棄領導權時,其它客戶端根據競選的前後順序(也即節點序號)成爲新 Leader,這也是公平模式的由來 延遲相對非公平模式要高,由於它必須等待特定節點獲得通知才能選出新的 Leader