ZooKeeper是一個分布式協調服務來管理大量的主機。協調和管理在分布式環境的一個服務是一個復雜的過程。ZooKeeper 簡單解決了其結構和API這個問題。ZooKeeper允許開發人員能夠專注於核心應用程序邏輯,而無需擔心應用程序的分布式特性。
ZooKeeper框架始建於“雅虎”,一個簡單而強大的方法用於訪問應用程序。后來 Apache ZooKeeper 成為用 Hadoop,HBase 的組織服務以及其他分布式架構的標准。例如,Apache HBase 使用 ZooKeeper 跟蹤分布式數據的狀態。
Apache ZooKeeper是由群集(組節點)之間進行相互協調,並保持強大的同步技術共享數據的服務。ZooKeeper本身是一個分布式應用寫入分布式應用提供服務。
ZooKeeper 提供的通用服務如下-
-
命名服務 − 確定在一個集群中的節點的名字。它類似於DNS,只不是過節點。
-
配置管理 − 系統最近加入節點和向上最新配置信息。
-
集群管理 − 加入/節點的群集和節點狀態實時離開。
-
節點領導者選舉 − 選舉一個節點作為領導者協調的目的。
-
鎖定和同步服務 − 鎖定數據,同時修改它。這種機制可以幫助自動故障恢復,同時連接其它的分布式應用程序。如Apache HBase。
-
高可靠的數據注冊表 − 一個或幾個節點的可用性的數據向下。
分布式應用程序提供了很多好處,但他們也帶來了一些復雜的,難以破解的挑戰。ZooKeeper框架提供了完整的機制來克服所有挑戰。競爭條件和死鎖使用故障安全同步的方式進行處理。另一個主要缺點是不一致的數據,ZooKeeper 使用原子性解決。
ZooKeeper的優點
下面是使用 ZooKeeper 的好處 -
-
簡單的分布式協調過程
-
同步 − 互斥和服務器進程之間的合作。這個過程有助於Apache HBase 的配置管理。
-
有序消息
-
序列化− 根據特定的規則進行編碼數據。確保應用程序不斷地運行。這種方法可以用來在MapReduce的協調隊列以執行正在運行的線程。
-
可靠性
-
原子性 − 數據傳輸成功或完全失敗,但沒有事務處理部分。
ZooKeeper的體系結構
看看下面的圖。它描繪ZooKeeper 的“客戶端 - 服務器架構”。
ZooKeeper 架構的一部分組件如下表中所解釋。
部分 | 描述 |
---|---|
Client | 客戶端,在我們的分布式應用集群的一個節點,從服務器獲取信息。對於一個特定的時間間隔,每個客戶端將消息發送到服務器,以讓服務器都知道客戶機是活的。 同樣,服務器會發送一個確認當客戶端連接。如果沒有從所連接的服務器的響應,客戶端自動重定向消息到另一個服務器 |
Server | 服務器,ZooKeeper集成的一個節點,提供所有的服務提供給客戶。給出應答客戶,告知該服務器還活着 |
合組 | ZooKeeper 服務器組。節點所需要形成的合奏的最小數目為3 |
Leader | 它執行自動恢復,如果任何連接的節點的故障的服務器節點。領導者服務啟動 |
Follower | 遵循領導指示服務器節點 |
分層命名空間
下圖顯示了用於內存中表示 ZooKeeper 文件系統的樹形結構。 ZooKeeper節點被稱為znode。每個znode由一個名稱識別,並通過路徑(/)序列隔開。
-
在圖中,首先有一個根znode,它由“/”分隔。在根下,有兩個邏輯命名空間 config 和 workers。
-
在config命名空間用於集中配置管理以及 workers 命名空間用於命名。
-
在 config 命名空間下,每個znode可以存儲高達 1MB 的數據。這類似於UNIX文件系統,不同的是父 znode 也可以存儲數據。這種結構的主要目的是存儲同步數據以及描述znode的元數據。這種結構被稱為 ZooKeeper數據模型。
在 ZooKeeper 數據模型中每個 znode 維護一個 stat 結構。 一個統計(stat )只是提供了一個 znode 元數據。 它由版本號,動作控制列表(ACL),時間戳和數據長度組成。
-
版本號 − 每個znode都有一個版本號,這意味着每個相關的時間使用節點改變數據,其相應的版本號也將增加。使用版本號是重要的,在多個 zookeeper 的客戶端正在努力通過相同znode執行操作。
-
動作控制列表(ACL) −ACL是基本的身份驗證機制,用於訪問znode。它管理所有的znode讀寫操作。
-
時間戳 − 時間戳表示過去時間,從znode創建和修改起算。它通常以毫秒表示。ZooKeeper 確定每次從“事務ID”(zxid)更改znodes。Zxid是獨特的,為每個事務處理維持時間,使您可以輕松地識別從一個請求到另一個請求經過的時間。
-
數據長度 − 存儲在 znode 數據的合計量是數據長度。可以存儲的最大數據容量為1MB。
Znodes 類型
Znodes 被歸類為持久性,順序和短暫。
-
持久性znode − 持久性 znode 處於活動狀態,即使客戶端,它創造了特定的 znode。默認情況下,所有的 znodes 是持久的,除非另有說明。
-
短暫znode − 短暫znodes活躍,直到客戶端還活着。當客戶端被從 ZooKeeper 集合斷開連接,然后znodes自動刪除。由於這個原因,只有短暫znodes不允許再有一個子。如果短周期znode被刪除,那么下一個合適的節點,將填補其位置。短暫znodes 發揮在領導選舉中起重要作用。
-
連續znode − 連續znodes可以是持久或短暫的。當一個新的znode作為連續znode創建的,則 ZooKeeper 通過將10位的序列號為原始名稱設置znode的路徑。例如,如果使用路徑 /myapp 來創建一個znode作為連續znode,ZooKeeper將改變路徑 /myapp0000000001並設置一個序列號為0000000002。如果兩個連續znodes同時被創建,ZooKeeper從來不使用相同數量在每個znode上。連續znodes在鎖定和同步中起到重要作用。
會話
會話對於 ZooKeeper 操作是非常重要的。請求在會話 FIFO 順序執行。當一個客戶端連接到服務器,會話將建立一個會話ID並分配給客戶端。
客戶端在特定的時間間隔發送心跳來保持會話有效。如果 ZooKeeper 從客戶端接收檢測信號超過在服務的開始指定的期間(會話超時),它認為該客戶死亡。
會話超時通常以毫秒表示。當一個會話因任何原因而結束,該會話期間短暫創造了的 znodes 會被刪除。
監視
監視是一個簡單的機制,在ZooKeeper集合通知下以獲取客戶有關的變化。 客戶端可以設置監視,同時讀取特定znode。監視發送通知給注冊的客戶機對任何znode(在其上的客戶端寄存器)的變化。
節點改變時znode或子znode變化相關聯的數據也會被修改。監視只被觸發一次。如果客戶想要再次通知,則必須通過另一次讀操作來完成。當一個連接會話已過期,客戶端會從服務器斷開,並在相關的監視也將被刪除。
Zookeeper工作流
當ZooKeeper集合啟動時,它會等待客戶端連接。客戶端將連接到ZooKeeper的集合的其中一個節點。它可能是一個領導者或跟隨者節點。當客戶機連接時,該節點分配會話ID給特定的客戶端,並發送一個確認消息給客戶端。如果客戶端沒有得到確認,它會嘗試連接ZooKeeper集合的另一個節點。當連接到一個節點后,客戶端將以規則的間隔發送心跳到節點,以確保連接不會丟失。
-
如果客戶想要讀取特定的znode,它發送一個讀請求使用znode路徑的節點,所述節點從其自己的數據庫中獲取它返回所請求的znode。出於這個原因,讀取在動物園管理員集合中速度非常快。
-
如果客戶希望將數據存儲在ZooKeeper 集合,它發送znode路徑和數據到服務器。連接的服務器將請求轉發到領導者,那么領導者將重新發出書面請求到所有的追隨者。如果只有一個數節點成功響應,接着寫請求將成功及一個成功的返回代碼將被發送到客戶端。否則,寫請求將失敗。嚴格大部分節點被稱為定額。
ZooKeeper集合的節點
讓我們來分析ZooKeeper集合不同數量的節點的作用。
-
如果我們有一個節點,那么當該節點出現故障時ZooKeeper集合失敗。它有利於“單一失敗教程”,它不建議用在生產環境中。
-
如果我們有兩個節點,一個節點出現故障,我們也沒有“多數”,因為二分之一並不是一個大多數。
-
如果我們有三個節點及其一個節點發生故障,我們有大多數,因此它是最低要求。它強制 ZooKeeper 集合在實際生產環境中至少有三個節點。
-
如果我們有四個節點及其有當兩個節點失敗,它類似於有三個節點。額外的節點沒有任何作用,因此,最好是單數增加節點,例如,3, 5, 7.
我們知道,寫處理它比在 ZooKeeper 集合讀過程是昂貴的,由於所有的節點需要寫相同的數據在其數據庫中。因此,最好是具有節點(3,5或7)比具有大量節點的一個平衡的環境的數量少。
下圖描述了ZooKeeper 的工作流程以及在隨后的表說明了其不同的組件。

組件 | 描述 |
---|---|
寫入 | 寫過程是由領導節點處理。領導者轉發寫請求到所有znodes及其等待來自znodes應答。如果一半的znodes的回復,那么寫入過程就完成了。 |
讀取 | 讀取在內部由特定連接znode進行的,所以沒有必要與集群交互。 |
復制數據庫 | 它是用來將數據存儲在zookeeper。每個znode都有自己的數據庫及其每個znode 在一致性的作用下,每次有相同的數據。 |
領導者(節點) | 領導者是由Znode負責處理寫請求。 |
追隨者(節點) | 追隨者收到來自客戶端的寫請求,並將其轉發到領導znode。 |
請求處理器 | 目前僅在領導節點。它從跟隨節點的請求支配寫入。 |
原子廣播 | 負責從領導節點到從節點廣播更改。 |
Zookeeper領導人選舉
讓我們來分析一下一個領導節點在ZooKeeper集合的選舉。考慮集群中有N多的節點。領導人選舉的過程如下 −
-
所有節點創建一個順序,znode具有相同路徑,/app/leader_election/guid_。
-
ZooKeeper 的集合將追加的10位序列號的路徑,創造了 znode 將會是 /app/leader_election/guid_0000000001, /app/leader_election/guid_0000000002, ...等。
-
對於給定的實例,它在znode創建最小數量的節點成為領導者以及所有其他節點的追隨者。
-
每一個追隨者節點監控下一個最小號的znode。
及其該節點創建znode /app/leader_election/guid_0000000007 將監控znode /app/leader_election/guid_0000000006.
-
如果領導停機,接着其對應的znode/app/leader_electionN被刪除。
-
跟隨節點接下來將通過觀察者得到關領導去除的通知。
-
跟隨節點接下來會檢查是否有其他znodes用最小數量。 如果沒有,接着它將承擔領導者的角色。否則,它會找到哪些用最小數創造了znode作為領導者的節點。
-
同樣,其他所有跟隨節點選舉創造了znode用最小數作為領導者的節點。
領導人選舉時,它從頭開始做一個復雜的過程。但ZooKeeper服務,使得它非常簡單。讓我們在接下來的章節介紹 ZooKeeper 安裝和開發。
Zookeeper CLI
ZooKeeper 命令行界面(CLI)是用來與 ZooKeeper 集成作開發進行交互的。這是在調試和使用不同的選項時的工作有用。
為了執行ZooKeeper的CLI操作, ZooKeeper服務器首先要啟動 (“bin/zkServer.sh start”) , 然后使用 ZooKeeper 客戶端 (“bin/zkCli.sh”). 當客戶端啟動后,可以執行以下操作 -
- 創建znodes
- 獲取數據
- 監視 znode 變化
- 設置數據
- 創建 znode 的子 znode
- 列出一個 znode 的子 znode
- 檢查狀態
- 刪除一個 znode
現在,讓我們一個個用一個例子地來看上面的命令。
創建Znodes
由一個給定的路徑來創建znode。flag參數指定了創建的 znode 是否為短暫的,持久的,或連續的。默認情況下,所有的 znodes是持久的。
-
短暫 znodes(flag: e)當會話過期或當客戶端斷開連接將被自動刪除。
-
連續 znodes 保證 znode 路徑是唯一的。
-
ZooKeeper集成將沿着添加序列號使用10位填充到znode路徑。例如,znode路徑 /myapp 將被轉換為 /myapp0000000001 以及下一個序列號將是 /myapp0000000002. 如果沒有指定flag,那么 znode 是持久的。
語法
create /path /data
示例
create /FirstZnode “Myfirstzookeeper-app”
輸出結果
[zk: localhost:2181(CONNECTED) 0] create /FirstZnode “Myfirstzookeeper-app” Created /FirstZnode
要創建一個連續znode,如下圖所示添加 -s 標志。
語法
create -s /path /data
示例
create -s /FirstZnode second-data
輸出
[zk: localhost:2181(CONNECTED) 2] create -s /FirstZnode “second-data” Created /FirstZnode0000000023
要創建一個臨時Znode,添加-e標志,如下圖所示。
語法
create -e /path /data
示例
create -e /SecondZnode “Ephemeral-data”
輸出
[zk: localhost:2181(CONNECTED) 2] create -e /SecondZnode “Ephemeral-data” Created /SecondZnode
記住,當丟失一個客戶端連接,在臨時 znode 將被刪除。可以通過退出 ZooKeeper CLI 嘗試,然后重新打開命令行。
獲取數據
它返回 znode 的相關數據和指定 znode 元數據。這里將得到信息,例如當數據最后一次修改,在那里它被修改和有關數據的信息。此外 CLI 還用於分配監視顯示通知有關的數據。
語法
get /path
示例
get /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0
要訪問順序znode,必須輸入znode的完整路徑。
示例
get /FirstZnode0000000023
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode0000000023 “Second-data” cZxid = 0x80 ctime = Tue Sep 29 16:25:47 IST 2015 mZxid = 0x80 mtime = Tue Sep 29 16:25:47 IST 2015 pZxid = 0x80 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 13 numChildren = 0
監視
監視顯示通知當指定znode或znode的子數據變化。只能在 get 命令中設置監視。
語法
get /path [watch] 1
示例
get /FirstZnode 1
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode 1 “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0
輸出類似於正常get命令,但它會在后台等待節點改變。
設置數據
設置指定znode的數據。當你完成設置操作,就可以使用get CLI命令檢查數據。
語法
set /path /data
示例
set /SecondZnode Data-updated
輸出
[zk: localhost:2181(CONNECTED) 1] get /SecondZnode “Data-updated” cZxid = 0x82 ctime = Tue Sep 29 16:29:50 IST 2015 mZxid = 0x83 mtime = Tue Sep 29 16:29:50 IST 2015 pZxid = 0x82 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x15018b47db00000 dataLength = 14 numChildren = 0
如果分配監視選項在get命令(之前的命令),則輸出將類似如下 -
輸出
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Mysecondzookeeper-app” WATCHER: : WatchedEvent state:SyncConnected type:NodeDataChanged path:/FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x84 mtime = Tue Sep 29 17:14:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0
創建子znode
創建子znode類似於創建新的znodes。唯一的區別在於,子 znode 的路徑將包含有父路徑。
語法
create /parent/path/subnode/path /data
示例
create /FirstZnode/Child1 firstchildren
輸出
[zk: localhost:2181(CONNECTED) 16] create /FirstZnode/Child1 “firstchildren” created /FirstZnode/Child1 [zk: localhost:2181(CONNECTED) 17] create /FirstZnode/Child2 “secondchildren” created /FirstZnode/Child2
列出子znode
該命令用於列出和顯示子 znode 。
語法
ls /path
示例
ls /MyFirstZnode
輸出
[zk: localhost:2181(CONNECTED) 2] ls /MyFirstZnode [mysecondsubnode, myfirstsubnode]
檢查狀態
狀態描述了指定znode的元數據。它包含詳細信息,如時間戳,版本號,訪問控制列表,數據長度和子znode。
語法
stat /path
示例
stat /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 1] stat /FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 17:14:24 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0
刪除Znode
刪除指定znode和遞歸刪除所有的子znode。這只有在znode可用時發生。
語法
rmr /path
示例
rmr /FirstZnode
輸出
[zk: localhost:2181(CONNECTED) 10] rmr /FirstZnode [zk: localhost:2181(CONNECTED) 11] get /FirstZnode Node does not exist: /FirstZnode
刪除(刪除/路徑)命令類似remove命令,但它僅適用於無子znode的znode。