ZooKeeper系列文章:https://www.cnblogs.com/f-ck-need-u/p/7576137.html#zk
ZooKeeper: 分布式協調服務
ZooKeeper是一個開源的為分布式應用提供分布式協調的服務。它公開了一組簡單的原語,分布式應用程序可以基於這些原語實現更高級別的服務,包括同步、維護配置、組和命名。它的設計易於編程,它使用一個遵循文件系統中常見的目錄樹結構的數據模型。它在Java環境中運行,對Java和C都有綁定。
協調服務是出了名的難。它們特別容易出錯,如競態條件和死鎖。ZooKeeper背后的動機是讓分布式應用從零開始實現一站式協調服務。
設計目標
ZooKeeper很簡單。通過共享一個類似於標准文件系統結構的層次名稱空間,Zookeeper允許分布式進程進行各自的協調。名稱空間中包含了注冊數據——即所謂的znodes,它們類似於文件和目錄。Zookeeper不像文件系統,目的是數據存儲,Zookeeper的數據存放在內存中,這意味着zookeeper具有高吞吐量和低延遲的優點。
ZooKeeper非常注重高性能、高可用性、嚴格有序的訪問。ZooKeeper的性能方面意味着它可以在大型分布式系統中使用。可靠性方面使它不會出現單點故障。嚴格有序意味着可以在客戶端實現復雜的同步原語。
ZooKeeper是復制的。與它所協調的分布式進程一樣,ZooKeeper本身也打算在一組主機上進行復制。
組成ZooKeeper的每個server之間都必須互相了解。每個server都維護狀態信息(state)的內存映像,以及持久存儲中的事務日志和快照。只要ZooKeeper中的大多數server可用,ZooKeeper服務就可用。
每個client連接到ZooKeeper集群中的某個server。客戶端會與之建立TCP連接,通過該TCP連接來發送請求、獲取響應、獲取觀察事件(watch events)以及發送心跳。如果TCP連接中斷,客戶端將連接到另一個server。
ZooKeeper是有序的。ZooKeeper給每次更新都貼上一個數字,這個數字反映了所有ZooKeeper事務的順序。后續操作可以使用這個順序來實現高級抽象,例如同步原語。
ZooKeeper速度很快,特別是在"以讀為主"的工作負載中尤其快速。ZooKeeper應用程序可用在數千台機器上運行,在多讀少寫(比率在10:1左右)的環境中表現最好。
數據模型和有層次的名稱空間
ZooKeeper提供的名稱空間非常類似於標准文件系統。名稱是由斜線(/)分隔的路徑元素序列。在ZooKeeper名稱空間中的每一個節點都是通過一條路徑來標識的。
節點和臨時節點
與標准文件系統不同的是,ZooKeeper名稱空間中的每個節點(路徑)都可以有與之關聯的數據,子節點也如此(譯注:即節點的路徑自身攜帶數據)。這就像是一個既文件也目錄的文件系統。(ZooKeeper的目的是存儲協調數據:狀態信息、配置、位置信息等,所以每個節點存儲的數據通常都很小,一般都是kb級別的)。我們使用術語znode來明確說明我們正在討論ZooKeeper數據節點。
znode維護一個包含數據更改版本號、ACL更改版本號和時間戳版本號的stat結構,以便能夠做緩存驗證和協調更新。每當znode的數據發生變化,版本號就會增加。例如,客戶端每次檢索數據的同時,也會接收數據的版本信息。
名稱空間中,每個znode上存儲的數據的讀、寫操作都是原子性的。讀操作會獲取與znode關聯的所有數據,寫操作會替換所有數據。每個節點都有一個訪問控制列表(ACL),限制誰可以做什么。
ZooKeeper也有臨時節點(ephemeral nodes)的概念。只要創建這些znode的會話(session)是活動的,這些znode就存在。當會話結束時,znode被刪除。當您想要實現[tbd]時,臨時節點非常有用。
協調更新和watch
ZooKeeper支持觀察(watch)的概念。客戶端可以在znode上設置一個watch。當znode更改時,將觸發並刪除一個watch。當watch被觸發時,客戶端會收到一個通知znode已更改的數據包。如果客戶端和ZooKeeper server之間的TCP連接中斷了,客戶端將收到本地通知。這些可用於[tbd]。
ZooKeeper的保證
ZooKeeper快速又簡單。但由於它的目標是作為構建更復雜服務(如同步)的基礎,所以它要實現一些保證。包括:
- 序列的一致性:(Sequential Consistency)來自客戶端的更新將按照發送的順序進行應用。
- 原子性:(Atomicity)更新要么成功,要么失敗。沒有部分成功、失敗的結果。
- 單系統映像:(Single System Image)無論連接到ZooKeeper中的哪個server,客戶端都將看到相同的服務視圖。
- 可靠性:(Reliability)一旦應用了更新,它將一直持續到有客戶端對它做了覆蓋更新。
- 時效性:(Timeliness)保證客戶端看到的視圖在一定的時間范圍內是最新的。
更多信息,以及如何使用它們,請參見[tbd]。
Simple API
ZooKeeper的一個設計目標是提供非常簡單的編程接口。因此,它只支持以下幾個操作:
create
:在樹中的某個位置創建一個節點。delete
:刪除一個節點。exists
:測試一個節點是否存在。get data
:讀取節點數據。set data
:向節點中寫入數據。get children
:檢索某節點的子節點列表。sync
:等待要傳播的數據。
更深入內容,以及如何使用它們實現更高級別的操作,請參閱[tbd]。
Implementation
下圖顯示了ZooKeeper服務的高層組件。除了request processor,構成ZooKeeper Service的每個server都復制自己的每個組件副本。
replicated database是包含整個數據樹(data tree)的內存數據庫。每次發起的更新都會將其記錄到磁盤中的日志,以便以后能夠進行恢復(recovery),在更新真正應用到內存數據庫之前,還會先將更新序列化到磁盤中。
每個ZooKeeper server都會為客戶端提供服務。客戶端連接到一個server來提交request。對於read request,每個server會從本地database的副本中提供服務。對於write request,這些請求會更改服務狀態,它們由協商協議(agreement procotol)來處理。
作為協商協議(agreement procotol)的一部分,所有來自客戶端的write request都被轉發到一個稱為leader的server上。ZooKeeper中的其它server,都稱為follower,它們接收來自leader的消息,並傳遞那些達成一致的消息。消息層(messaging layer)負責在leader故障時選舉新的leader,並剩余的follower和新的leader保持同步。
ZooKeeper使用一個自定義的原子消息傳遞協議。由於該消息層是原子性的,ZooKeeper可以保證本地副本永遠不會出現分歧。當leader收到write request時,它會計算當寫操作被執行時系統狀態,並將其轉換為帶有該狀態的事務。
ZooKeeper的使用
ZooKeeper的編程接口很簡單。但有了它,您可以實現更高級的操作,比如同步原語、組成員關系(group membership)、所有權(ownership)等等。更多信息請參閱[tbd]。
ZooKeeper性能
ZooKeeper具有高性能。真的如此嗎?雅虎ZooKeeper的開發團隊的研究結果已經表明確實如此。(參見下圖)。當讀操作比寫操作更頻繁時,ZooKeeper的性能非常高,因為寫操作會調用所有節點的狀態同步。(協調服務的典型情況就是多讀少寫)。
注意:在3.2版本中,r/w的性能比3.1版本提高了大約2倍。