zookeeper原理及應用

HeyZero發表於2017-12-07

ZooKeeper是一個分散式的,開放原始碼的分散式應用程式協調服務,是GoogleChubby一個開源的實現。

Apache ZooKeeper is an effort to develop and maintain an open-source server which enables highly reliable distributed coordination.

原理介紹和說明

  • 一致性演算法

ZooKeeper以Fast Paxos(帕克索斯)演算法為基礎,讓叢集中的每個zk例項資料保持一致。一般部署叢集,機器數設定為奇數個,更容易滿足>N/2的投票條件。

  • 儲存模型
/
├── app1
│   ├── p_1
│   ├── p_2
│   └── p_3
└── app2
複製程式碼

類似作業系統資料夾的樹型模型,與資料夾的區別在於,每個節點上可儲存資料(不超過1M),每個節點上的資料可帶版本號。

  • zNode節點型別

2個劃分維度:按節點是否可持久化儲存,分為持久節點與臨時節點;按節點序號是否可順序遞增(類似mysqlauto_increment),分為順序節點及非順序節點,

注:3.6.0版本以後,還新增了Container Nodes(容器節點),該節點的特點是,如果其下的所有子節點都被刪除,該節點也會在將來某個時間被刪除。

ZooKeeper has the notion of container nodes. Container nodes are special purpose nodes useful for recipes such as leader, lock, etc. When the last child of a container is deleted, the container becomes a candidate to be deleted by the server at some point in the future.

持久節點 (client建立持久節點後,就算與zk斷開,節點仍然儲存在zk)

持久順序節點 (eg: /order/quartz/wm000001 , /order/quartz/wm000002, /order/quartz/wm000003...)

臨時節點 (clientzk斷開連線後,節點自動刪除)

臨時順序節點

  • 事件監聽
    • Created event (節點建立事件)
    • Deleted event (節點刪除事件)
    • Changed event (節點的資料變化事件) -zkClient.subscribeChildChanges(); //訂閱子節點的變化
    • zkClient.subscribeDataChanges();//訂閱某節點的資料變化(包括資料被刪除)事件
    • zkClient.subscribeStateChanges();//訂單狀態變化(狀態包括:連線,斷開,認證失敗等等)

以上為常用事件,其它事件請參考官方文件。實際使用中,很少用原生寫法來監聽事件,而是藉助一些第三方的開源zk客戶端,比如zkClient來監聽事件。

  • ACL(Access Control List)許可權控制

    • 每個節點有5種操作許可權:Create、Read、Write、Delete、Admin 簡稱crwda。其中:Delete是指對子節點是否具有刪除許可權,其它4種許可權指對自身節點的操作許可權。
    • 身份認證方式:world:預設方式,無限制,全世界均能訪問。auth: 在上下文中新增授權使用者。digest: 使用者名稱/密碼認證ip: ip地址認證

應用場景

  • 應用場景1:分散式配置

zookeeper原理及應用

要點:配置資訊儲存在dbzk中(保險起見,資料安全性更高),弄一個後臺管理介面,對配置修改後,先儲存到db,然後同步寫入zk的節點中。應用啟動時,先連到zk上讀取節點中的配置,同時監聽節點的資料變化,當配置變化時,得到實時通知。

  • 應用場景2:消除單點故障(Single Point of Failure,SPOF)
└── ./OrderNoService
        ├── A0000001
                10.0.0.1:8001
        └── A0000002
                10.0.0.2:8001
複製程式碼

多個服務例項,啟動時在zk上臨時順序節點,服務的呼叫方約定取最小節點為Master,當master掛掉後,節點自動刪除,呼叫方得到事件通知,取新的最小節點來呼叫(相當於slave提升為master)

  • 應用場景3:去中心化
    zookeeper原理及應用

上圖中,左邊為傳統中心化的架構,缺點是每次有新的服務例項加入或下線,都要調整nginx中心節點的配置(不管是人工,還是藉助工具自動),不利於雲時代的動態彈性調整,而且整體的可用性強依賴於中心節點,一旦中心節點(中心叢集)全掛掉,系統就不可用了。

  • 應用場景4:分散式鎖
Order
    └── 3456890
        ├── 000001
        ├── 000002
        └── 000003
複製程式碼

原理:以多個程式執行例項同時在處理訂單3456890為例,每個程式執行例項處理前,建立一個臨時順序節點,然後檢查自己建立的節點是否為最小,如果不是,表明沒搶到鎖,如果是,表示搶到了鎖,搶到鎖的程式處理完以後,刪除該節點表示釋放鎖。同時,其它處於等候狀態的程式,為了實時得到鎖的釋放通知,均監聽父節點Order/3456890的子節點變化,發現子節點變化時,重複剛才的檢測過程,直到自己建立的節點變成最小為止。 與redis SETNX之類的分散式鎖相比,zk的分散式鎖,還能實現解決Top N之類的有限資源競爭問題(類似併發中的訊號量)。比如:一堆程式要列印,但是隻有2臺印表機(或者列印佇列的長度只有2,最多同時只能允許2個程式提交列印任務), 類似剛才的思路 ,可以檢測最小的前2個節點,只有建立最小前2個節點的程式,才認為是拿到了訊號,允許提交列印任務。

  • 應用場景5:分散式佇列
Queue
    └── Queue1
        ├── 000001
        ├── 000002
        └── 000003
複製程式碼

如上圖,建立Queue/Queue1做為一個佇列(或Topic),然後每建立一個順序節點,視為一條訊息(節點儲存的資料即為訊息內容),生產者每次建立一個新節點,做為訊息傳送,消費者監聽Queue1的子節點變化(或定時輪詢),每次取最小節點當做消費訊息,處理完後,刪除該節點。相當於實現了一個FIFO(先進先出)的佇列。 注:zk框架強制的是CP(一致性),而非專為高併發、高效能場景設計的,如果在高併發,qps很高的情況下,分散式佇列需酌情考慮。

  • 應用場景7:生成分散式唯一id
Order
      └── OrderId
        ├── 000001
        ├── 000002
        └── 000003
複製程式碼

思路:每次要生成一個新Id時,建立一個持久順序節點,建立操作返回的節點序號,即為新Id,然後把比自己節點小的刪除即可。

終篇

目前很多開源專案,幾乎都是或多或少依賴zookeeper,比如:dubbo,disconf,kafka,...

分散式環境中,zk能用於什麼場景,基本上取決於開發人員的想象力!

相關文章