Zookeeper
Zookeeper:一個為分散式應用設計的分散式協調服務
ZooKeeper是一款開源的分散式應用
的分散式協調服務
。它包含一個簡單的原語集
,分散式應用程式可以基於它實現同步服務,配置維護和命名服務等。Zookeeper 設計很容易進行程式設計,它使用一種類似於檔案系統的目錄樹結構的資料模型,以 java 方式執行,有 java 和 c 的繫結(binding)。
協調服務
是非常難以被正確實現的。他們特別容易產生諸如競態條件、死鎖等錯誤。ZooKeeper背後的動機是為分散式應用程式減輕從零開始實現協調服務的難度。
設計目標
Zookeeper是非常簡單的。
ZooKeeper允許分散式程式通過與標準檔案系統類似組織的共享層級名稱空間來相互協調。名稱空間被稱為znode
的資料記錄組成,用ZooKeeper的說法,這些記錄和標準檔案系統中的檔案和目錄非常相似。與典型的用於儲存的檔案系統不同,ZooKeeper資料儲存在記憶體中,這意味著ZooKeeper可以實現高吞吐量和低延遲。
Zookeeper的實現著重於高效能、高可用性和嚴格的順序訪問。ZooKeeper的效能方面意味著它可以用於大型分散式系統。可靠性方面使它不會造成單點故障。嚴格的排序意味著可以在客戶端實現複雜的同步原語。
Zookeeper 是複製的(replicated)
就像它協調的分散式程式一樣,Zookeeper 自身也在被稱為“ensemble”的一組主機之間進行復制。
組成 Zookeeper 服務(Service)的每個伺服器(server)之間都必須相互瞭解對方。他們維護一個記憶體狀態圖,以及一個持久儲存的事務日誌和快照。只要這些伺服器(servers)中大多數是可用的,整個ZooKeeper服務就是可用的。客戶端(client)連線到任意一臺ZooKeeper伺服器。客戶端維護一個TCP連線,通過它傳送請求、獲取響應、獲取監視事件以及傳送心跳。如果到伺服器的TCP連線中斷,客戶端將連線到其他不同的伺服器。
Zokeeper是有順序的
ZooKeeper使用反映所有ZooKeeper事務順序的數字來標記每個更新。後續操作可以使用該次序來實現更高階別的抽象,例如同步原語。
ZooKeeper 是快速的
在應對以“讀”為主的負載時尤其地快速。ZooKeeper應用程式在數千臺機器上執行,並且在讀取比寫入更為普遍的情況下,效能表現最佳,比例約為10:1。
Zookeeper資料模型和層級名稱空間
ZooKeeper提供的名稱空間與標準檔案系統非常相似。路徑是由斜槓/
分隔的一系列元素。 ZooKeeper名稱空間中的每個節點都由一個路徑標識。
Zookeeper預設節點
和臨時節點
與標準檔案系統不同的是,ZooKeeper名稱空間中的每個節點都可以擁有與其相關的資料以及子節點。這就像一個檔案系統中可以存在一個檔案或一個目錄。ZooKeeper被設計用來儲存相關的協調資料,如狀態資訊、配置、位置資訊等等,所以每個節點上儲存的資料通常都很小,在位元組(byte)到千位元組(kb)範圍內。我們使用術語znode來清楚地說明我們正在討論ZooKeeper資料節點。
Znode 維護了一個狀態(stat
)結構,其中包含了表示資料改變、訪問控制列表(ACL)改變的版本號、時間戳,可用於快取校驗、協調更新。每當一個znode的資料發生變化,版本號就會增加。例如,每當客戶端檢索資料時,客戶端也會接收到相應資料的版本資訊。
儲存在名稱空間中每個節點上的資料是以原子方式讀取和寫入的。讀取一個znode將獲得其全部的資料,而寫入則替換其全部的資料。
ZooKeeper也有臨時節點的概念。當建立臨時節點的客戶端會話一直保持活動,瞬時節點就一直存在。而當會話終結時,瞬時節點被刪除。
Zookeeper條件更新
和監視
(watches)
ZooKeeper 支援“監視”(watches)的概念。客戶端可以在znode上設定一個監視(watch)。當 znode改變時,監視(watch)將被觸發並移除。當監視(watch)被觸發時,當“監視”被觸發時,客戶端會收到一個描述了 znode 的變更的資料包。如果客戶端和Zookeeper伺服器之間的連線斷開時,客戶端將會收到一個本地通知。
Zookeeper保證
(Guarantees)
Zookeeper非常地快速也非常簡單。不過,由於它的目標是作為構建諸如“同步”這類更復雜服務的基礎,它提供了一些的一組保證:
- 順序一致性 - 來自客戶端的更改請求將會按照它們的傳送的順序被應用。
- 原子性 - 更改要麼成功,要麼失敗,不會存在部分成功、部分失敗的結果。
- 單一系統映像 - 客戶端會看到 Zookeeper 服務的相同的檢視,而無論它們連到具體哪一個伺服器上
- 可靠性 - 一旦一次更改請求被應用,更改的結果就會被持久化,直到被下一次更改覆蓋。
- 及時性 - 客戶端看到的系統檢視在一定的時間範圍內總是最新的。
簡單的API
ZooKeeper的一個設計目標是提供一個非常簡單的程式設計介面。 因此,它只支援這些操作:
-
create
在(名稱空間)樹的一個特定地址上建立一個節點。
-
delete
刪除一個節點。
-
exists
判斷某個路徑下是否存在該節點。
-
get data
獲取節點的資料。
-
set data
向節點寫入資料。
-
get children
檢索節點的子節點列表。
-
sync
等待資料傳播完成。
Zookeeper實現原理
ZooKeeper Components 顯示了ZooKeeper服務的高階元件。除Request Processor
外,構成ZooKeeper服務的每個伺服器都複製每個元件的副本。
replicated database
是一個記憶體資料庫,它包含了整顆資料樹。資料寫入在應用到記憶體資料庫之前,會先序列化到磁碟。
每一個 Zookeeper 伺服器都向客戶端提供服務,客戶端連線到一個確切的Zookeeper伺服器提交請求。讀請求從伺服器資料庫的本地拷貝中獲取。改變Zookeeper服務狀態的請求、寫入請求通過一個一致性協議進行處理。
作為協議的一部分,客戶端的所有寫入請求都被轉發到一個單獨的伺服器,該伺服器被稱為 leader。而其餘的伺服器,被稱為follower,從leader接收訊息提案(proposal)並對訊息的交付取得一致。訊息層維護leader失效時的更新替換以及leader和follower之間的同步。
Zookeeper 使用自定義的原子訊息協議。由於訊息層是原子的,Zookeeper可以保證本地的複製品不會不一致。當 leader收到一個寫入請求時,它計算系統所處的狀態以及何時應用寫入請求,並將此轉換為一個事務,包含新的狀態。
使用
Zookeeper 的程式設計介面特意地定義得很簡單。然而,通過這些程式設計介面可以更高階的操作,例如同步原語,成員分組,所有權,等等。
效能
Zookeeper 被設計為高效能。但實際是否如此呢?在雅虎研發中心的 Zookeeper 開發團隊的研究結果表明的確如此。(參見下圖:Zookeeper 吞吐量隨讀寫比的變化)。在“讀”多於“寫”的應用程式中尤其地高效能,因為“寫”會導致在所有的伺服器間同步狀態。(“讀”多於“寫”是協調服務的典型場景。)
Zookeeper 吞吐量隨讀寫比的變化
圖“Zookeeper 吞吐量隨讀寫比的變化” 是 Zookeeper3.2 版本執行於 Dual 2Gh Xeon + 2 個 15K RPM 的 SATA 硬碟驅動器的伺服器上的結果。一個驅動器用作 Zookeeper 專用的日誌裝置。快照寫到作業系統驅動器。寫請求是 1K 資料的寫入而讀請求是 1K 的資料讀取。“Servers”標出了 Zookeeper Ensemble 的大小,即組成 Zookeeper 服務的伺服器的數量。大約30臺其它的伺服器被用作模擬客戶端。Zookeeper Ensemble 被配置為不允許客戶端連線到 Leader 。注:3.2版本的讀/寫效能相對於3.1版本以前有最多達2倍的提升。
基準測試也表明了 Zookeeper 的可靠性。圖“錯誤發生的情況下的可靠性”展示了 Zookeeper 是如何應對各種不同的失效的。圖中標註的事件如下:
-
一個 Follower 失效然後恢復。
-
另一個不同的 Follower 失效然後恢復。
-
Leader 失效。
-
兩個 Follower 失效然後恢復。
-
另一個 Leader 失效。
可靠性
從這張圖中可以得到幾點重要的結果。首先,如果 follower 失效並快速恢復,Zookeeper 能夠維持高吞吐量,儘管存在失效。但也許更重要的是,leader選舉演算法使系統足夠快地恢復,避免了吞吐量的總體下降。從觀察結果來看,Zookeeper花了不到200毫秒的時間選舉出了一個新的 leader。第三,只要follower恢復,Zookeeper的吞吐量能夠再次上升到剛開始處理請求時的水平。關於ZooKeeper專案
Zookeeper 已經被成功地用在許多工業級的應用。在雅虎,Zookeeper被用作雅虎訊息中介軟體的協調和失效恢復服務,該系統是一個高伸縮性的釋出訂閱系統,管理著成千上萬的主題複製和資料分發。Zookeeper還被用在雅虎爬蟲的抓取服務上,用於管理失效恢復。許多雅虎的廣告系統也用 Zookeeper 實現可靠的服務。