天天看點

ZooKeeper介紹及典型使用場景

1 概述

 ZooKeeper(動物園管理者),顧名思義,是用來管理Hadoop(大象)、Hive(蜜蜂)、Pig(小豬)的管理者,同時Apache HBase、Apache Solr、LinkedIn Sensei等衆多項目中都采用了ZooKeeper。

 ZooKeeper曾是Hadoop的正式子項目,後發展成為Apache頂級項目,與Hadoop密切相關但卻沒有任何依賴。它是一個針對大型應用提供高可用的資料管理、應用程式協調服務的分布式服務架構,基于對Paxos算法的實作,使該架構保證了分布式環境中資料的強一緻性,提供的功能包括:配置維護、統一命名服務、狀态同步服務、叢集管理等。

 在分布式應用中,由于工程師不能很好地使用鎖機制,以及基于消息的協調機制不适合在某些應用中使用,是以需要有一種可靠的、可擴充的、分布式的、可配置的協調機制來統一系統的狀态。Zookeeper的目的就在于此。

2 特征

ZooKeeper是簡單的:ZooKeeper的核心是一個精簡檔案系統,它提供一些簡單的操作和一些額外的抽象操作,例如:排序和通知。

ZooKeeper是富有表現力的:ZooKeeper的原語操作是一組構件(building block),可用于實作很多協調資料結構和協定,例如:分布式隊列、分布式鎖和一組同級節點中的leader選舉(leader election)。

ZooKeeper具有高可用性:ZooKeeper運作在叢集上,被設計成具有較高的可用性,是以應用程式可以完全依賴它。ZooKeeper可以幫助系統避免出現單點故障,進而建構一個可靠的應用。

ZooKeeper采用松耦合互動方式:在ZooKeeper支援的互動過程中,參與者之間不需要彼此了解。例如:ZooKeeper可以被用作一個rendezvous機制,讓程序在不了解其他程序或網絡狀況的情況下能夠彼此發現并進行互動。參與協調的各方甚至可以不必同時存在,因為一個程序在ZooKeeper中留下一條消息,在該程序結束後,另外一個程序還可以讀取這條消息。

ZooKeeper是一個資源庫:ZooKeeper提供了一個關于通用協調模式實作和方法的開源共享存儲庫,能使程式員免于編寫這類通用的協定。所有人都能夠對這個資源庫進行添加和改進,随着時間的推移,會使每個人都從中收益。

ZooKeeper是高性能的:在它的誕生地Yahoo!公司,對于以寫為主的工作負載來說,ZooKeeper的基準吞吐量已超過每秒10000個操作;對于正常的以讀為主的工作負載來說,吞吐量更是高出好幾倍。

3 ZooKeeper的資料模型

了解ZooKeeper的一種方法是将其看做一個具有高可用性的檔案系統。但這個檔案系統中沒有檔案和目錄,而是統一使用節點(node)的概念,稱為znode。znode既可以儲存資料(如同檔案),也可以儲存其他znode(如同目錄)。所有的znode構成一個階層化的資料結構,。

Persistent Nodes: 永久有效地節點,除非client顯式的删除,否則一直存在

Ephemeral Nodes: 臨時節點,僅在建立該節點client保持連接配接期間有效,一旦連接配接丢失,zookeeper會自動删除該節點

Sequence Nodes: 順序節點,client申請建立該節點時,zk會自動在節點路徑末尾添加遞增序号,這種類型是實作分布式鎖,分布式queue等特殊功能的關鍵

 ZooKeeper是Hadoop的正式子項目,與Hadoop密切相關但卻沒有任何依賴。它是一個針對大型應用提供高可用的資料管理、應用程式協調服務的分布式服務架構,基于對Paxos算法的實作,使該架構保證了分布式環境中資料的強一緻性,提供的功能包括:配置維護、統一命名服務、狀态同步服務、叢集管理等。

4 ZooKeeper典型使用場景

4.1 資料釋出于訂閱

4.1.1 特性、用法

釋出與訂閱即所謂的配置管理,顧名思義就是将資料釋出到zk節點上,供訂閱者動态擷取資料,實作配置資訊的集中式管理和動态更新。例如:全局的配置資訊、位址清單等。

4.1.2 具體用法

索引資訊和叢集中機器節點狀态放在zk的一些指定節點,供各個用戶端訂閱使用。

系統日志(經處理後)存儲,這些日志通常2-3天後清除。

應用中用到的一些配置資訊集中管理,在應用啟動的時候主動來擷取一次,并在節點上注冊一個Watcher,以後每次配置有更新,實時通知到應用,擷取最新的配置資訊。

業務邏輯中需要用到的一些全局變量,比如一些消息中間件的消息隊列通常有個offset,這個offset存放在zk上,這樣叢集中每個發送者都能知道目前的發送進度。

系統中有些資訊需要動态擷取,并且還會存在人工手動去修改這個資訊。以前通常是暴露出接口,例如JMX接口,有了zk後,隻要将這些資訊存放到zk節點上即可。

4.2 命名服務

4.2.1 特性、用法

這個主要是作為分布式命名服務,通過調用zk的create node api,能夠很容易建立一個全局唯一的path,可以将這個path作為一個名稱。

4.3 分布通知/協調

4.3.1 特性、用法

ZooKeeper中特有的watcher注冊于異步通知機制,能夠很好的實作分布式環境下不同系統之間的通知與協調,實作對資料變更的實時處理。使用方法通常是不同系統都對zk上同一個znode進行注冊,監聽znode的變化(包括znode本身内容及子節點内容),其中一個系統update了znode,那麼另一個系統能夠收到通知,并做出相應處理。

使用ZooKeeper來進行分布式通知和協調能夠大大降低系統之間的耦合。

4.3.2 具體用法

心跳檢測機制:檢測系統和被測系統之間并不直接關聯起來,而是通過zk上某個節點關聯,大大減少系統耦合。

系統排程模式:某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台做的一些操作,實際上是修改了zk上某些節點的狀态,而zk就把這些變化通知給它們注冊watcher的用戶端,即推送系統,于是,做出相應的推送任務。

工作彙報模式:一些類似于任務分發系統,子任務啟動後,到zk來注冊一個臨時節點,并定時将自己的進度進行彙報(将進度寫回這個臨時節點),這樣任務管理者就能夠實時指導任務進度。

4.4 分布式鎖

4.4.1 特性、用法

分布式鎖,主要得益于ZooKeeper保證資料的強一緻性,即zk叢集中任意節點(一個zk server)上系統znoe的資料一定相同。

鎖服務可以分為兩類:

保持獨占鎖:所有試圖來擷取這個鎖的用戶端,最終隻有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看做是一把鎖,通過create znode的方式來實作。所有用戶端都去建立/distribute_lock節點,最終成功建立的那個用戶端也即擁有了這把鎖。

控制時序鎖:所有試圖來擷取這個鎖的用戶端,最終都是會被安排執行,隻是有個全局時序了。與保持獨占鎖的做法類似,不同點是/distribute_lock已經預先存在,用戶端在它下面建立臨時有序節點(可以通過節點控制屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。zk的父節點(/distribute_lock)維持一份sequence,保證子節點建立的時序性,進而形成每個用戶端的全局時序。

4.5 叢集管理

4.5.1 特性、用法

叢集機器監控:這通常用于那種對叢集中機器狀态、機器線上率有較高要求的場景,能夠快速對叢集中機器變化做出響應。這樣的場景中,往往有一個監控系統,實時監測叢集機器是否存活。過去的做法通常是:監控系統通過某種手段(比如ping)定時檢測每個機器、或每個機器定時向監控系統發送心跳資訊。這種做法存在兩個弊端:1.叢集中機器有變動的時候,牽連修改的東西比較多。2.有一定的延遲。利用ZooKeeper,可以實作另一種叢集機器存活性監控系統:a.用戶端在節點x上注冊watcher,如果x的子節點發生變化,會通知該用戶端。b.建立EPHEMERAL類型的節點,一旦用戶端和伺服器的會話結束或過期,該節點就會消失。例如:監控系統在/clusterServers節點上注冊一個watcher,以後每動态加機器,就往/culsterServer下建立一個EPHEMERAL類型的節點:/clusterServer/{hostname}。這樣,監控系統就能實時知道機器的增減情況,至于後續處理就是監控系統的業務了。

Master選舉:在分布式環境中,相同的業務應用分布在不同的機器上,有些業務邏輯(例如一些耗時的計算、網絡I/O處理),往往需要讓整個叢集中的某一台機器進行執行,其餘機器可以共享這個結果,這樣可以減少重複勞動、提高性能。利用ZooKeeper的強一緻性,能夠保證在分布式高并發情況下節點建立的全局唯一性,即:同時有多個用戶端請求建立/currentMaster節點,最終一定隻有一個用戶端請求能夠建立成功。利用這個特性,就能很輕易的在分布式環境中進行叢集選取了。另外,這種場景演化一下,就是動态Master選舉。這就要用到 EPHEMERAL_SEQUENTIAL類型節點的特性了。上文中提到,所有用戶端建立請求,最終隻有一個能夠建立成功。在這裡稍微變化下,就是允許所有請求都能夠建立成功,但是得有個建立順序,于是所有的請求最終在zk上建立結果的一種可能情況是這樣: /currentMaster/{sessionId}-1、/currentMaster/{sessionId}-2、/currentMaster/{sessionId}-3……。每次選取序列号最小的那個機器作為Master,如果這個機器挂了,由于他建立的節點會馬上消失,那麼之後最小的那個機器就是Master了。

4.5.2 具體用法

在搜尋系統中,如果叢集中每個機器都生成一份全量索引,不僅耗時,而且不能保證彼此之間索引資料一緻。是以讓叢集中的Master來進行全量索引的生成,然後同步到叢集中其它機器。

Master選舉的容災措施是,可以随時進行手動指定master,就是說應用在zk在無法擷取master資訊時,可以通過比如http方式,向一個地方擷取master。

4.6 分布式隊列

4.6.1 特性、用法

隊列方面,有兩種方式:一種是正常的先進先出隊列,另一種是要等到隊列成員聚齊之後的才統一按序執行。

對于先進先出隊列,和分布式鎖服務中的控制時序場景基本原理一緻,這裡不再贅述。

第二種隊列其實是在FIFO隊列的基礎上作了一個增強。通常可以在/queue這個znode下預先建立一個/queue/num節點,并且指派為n(或者直接給/queue指派n),表示隊列大小,之後每次有隊列成員加入後,就判斷下是否已經到達隊列大小,決定是否可以開始執行了。這種用法的典型場景是,分布式環境中,一個大任務Task A,需要在很多子任務完成(或條件就緒)情況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那麼就去/taskList下建立自己的臨時時序節點(CreateMode.EPHEMERAL_SEQUENTIAL),當/taskList發現自己下面的子節點滿足指定個數,就可以進行下一步按序進行處理了。