ZooKeeper是一個高可用的分佈式數據管理與系統協調框架。基於對Paxos算法的實現,使該框架保證了分佈式環境中數據的強一致性,也正是基於這樣的特性,使得ZooKeeper解決不少分佈式問題。網上對ZK的應用場景也有很多介紹,本文將結合做者身邊的項目例子,系統地對ZK的應用場景進行一個分門歸類的介紹。node
值得注意的是,ZK並不是天生就是爲這些應用場景設計的,都是後來衆多開發者根據其框架的特性,利用其提供的一系列API接口(或者稱爲原語集),摸索出來的典型使用方法。所以,也很是歡迎讀者分享你在ZK使用上的奇技淫巧。算法
ZooKeeper典型應用場景一覽服務器 |
數據發佈與訂閱(配置中心)網絡 |
發佈與訂閱模型,即所謂的配置中心,顧名思義就是發佈者將數據發佈到ZK節點上,供訂閱者動態獲取數據,實現配置信息的集中式管理和動態更新。例如全局的配置信息,服務式服務框架的服務地址列表等就很是適合使用。session |
注意:在上面提到的應用場景中,有個默認前提是:數據量很小,可是數據更新可能會比較快的場景。併發 |
負載均衡負載均衡 |
這裏說的負載均衡是指軟負載均衡。在分佈式環境中,爲了保證高可用性,一般同一個應用或同一個服務的提供方都會部署多份,達到對等服務。而消費者就需要在這些對等的服務器中選擇一個來執行相關的業務邏輯,其中比較典型的是消息中間件中的生產者,消費者負載均衡。框架 |
消息中間件中發佈者和訂閱者的負載均衡,linkedin開源的KafkaMQ和阿里開源的metaq都是經過zookeeper來作到生產者、消費者的負載均衡。這裏以metaq爲例如講下: 消費負載均衡:分佈式 在消費過程當中,一個消費者會消費一個或多個分區中的消息,可是一個分區只會由一個消費者來消費。MetaQ的消費策略是:
在某個消費者故障或者重啓等狀況下,其餘消費者會感知到這一變化(經過 zookeeper watch消費者列表),而後從新進行負載均衡,保證全部的分區都有消費者進行消費。 |
命名服務(Naming Service) |
命名服務也是分佈式系統中比較常見的一類場景。在分佈式系統中,經過使用命名服務,客戶端應用可以根據指定名字來獲取資源或服務的地址,提供者等信息。被命名的實體一般能夠是集羣中的機器,提供的服務地址,遠程對象等等——這些咱們均可以統稱他們爲名字(Name)。其中較爲常見的就是一些分佈式服務框架中的服務地址列表。經過調用ZK提供的建立節點的 API,可以很容易建立一個全局惟一的path,這個path就能夠做爲一個名稱。 |
阿里巴巴集團開源的分佈式服務框架Dubbo中使用ZooKeeper來做爲其命名服務,維護全局的服務地址列表,點擊這裏查看Dubbo開源項目。在Dubbo實現中: 服務提供者在啓動的時候,向ZK上的指定節點/dubbo/${serviceName}/providers目錄下寫入本身的URL地址,這個操做就完成了服務的發佈。 服務消費者啓動的時候,訂閱/dubbo/${serviceName}/providers目錄下的提供者URL地址, 並向/dubbo/${serviceName} /consumers目錄下寫入本身的URL地址。 注意,全部向ZK上註冊的地址都是臨時節點,這樣就可以保證服務提供者和消費者可以自動感應資源的變化。 另外,Dubbo還有針對服務粒度的監控,方法是訂閱/dubbo/${serviceName}目錄下全部提供者和消費者的信息。 |
分佈式通知/協調 |
ZooKeeper中特有watcher註冊與異步通知機制,可以很好的實現分佈式環境下不一樣系統之間的通知與協調,實現對數據變動的實時處理。使用方法一般是不一樣系統都對ZK上同一個znode進行註冊,監聽znode的變化(包括znode自己內容及子節點的),其中一個系統update了znode,那麼另外一個系統可以收到通知,並做出相應處理 |
總之,使用zookeeper來進行分佈式通知和協調可以大大下降系統之間的耦合 |
集羣管理與Master選舉 |
利用ZooKeeper有兩個特性,就能夠實時另外一種集羣機器存活性監控系統:
例如,監控系統在 /clusterServers 節點上註冊一個Watcher,之後每動態加機器,那麼就往 /clusterServers 下建立一個 EPHEMERAL類型的節點:/clusterServers/{hostname}. 這樣,監控系統就可以實時知道機器的增減狀況,至於後續處理就是監控系統的業務了。
在分佈式環境中,相同的業務應用分佈在不一樣的機器上,有些業務邏輯(例如一些耗時的計算,網絡I/O處理),每每只須要讓整個集羣中的某一臺機器進行執行,其他機器能夠共享這個結果,這樣能夠大大減小重複勞動,提升性能,因而這個master選舉即是這種場景下的碰到的主要問題。 利用ZooKeeper的強一致性,可以保證在分佈式高併發狀況下節點建立的全局惟一性,即:同時有多個客戶端請求建立 /currentMaster 節點,最終必定只有一個客戶端請求可以建立成功。利用這個特性,就能很輕易的在分佈式環境中進行集羣選取了。 另外,這種場景演化一下,就是動態Master選舉。這就要用到?EPHEMERAL_SEQUENTIAL類型節點的特性了。 上文中提到,全部客戶端建立請求,最終只有一個可以建立成功。在這裏稍微變化下,就是容許全部請求都可以建立成功,可是得有個建立順序,因而全部的請求最終在ZK上建立結果的一種可能狀況是這樣: /currentMaster/{sessionId}-1 ,?/currentMaster/{sessionId}-2 ,?/currentMaster/{sessionId}-3 ….. 每次選取序列號最小的那個機器做爲Master,若是這個機器掛了,因爲他建立的節點會立刻小時,那麼以後最小的那個機器就是Master了。 |
|
分佈式鎖 |
分佈式鎖,這個主要得益於ZooKeeper爲咱們保證了數據的強一致性。鎖服務能夠分爲兩類,一個是保持獨佔,另外一個是控制時序。
|
分佈式隊列 |
隊列方面,簡單地講有兩種,一種是常規的先進先出隊列,另外一種是要等到隊列成員聚齊以後的才統一按序執行。對於第一種先進先出隊列,和分佈式鎖服務中的控制時序場景基本原理一致,這裏再也不贅述。 第二種隊列實際上是在FIFO隊列的基礎上做了一個加強。一般能夠在 /queue 這個znode下預先創建一個/queue/num 節點,而且賦值爲n(或者直接給/queue賦值n),表示隊列大小,以後每次有隊列成員加入後,就判斷下是否已經到達隊列大小,決定是否能夠開始執行了。這種用法的典型場景是,分佈式環境中,一個大任務Task A,須要在不少子任務完成(或條件就緒)狀況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那麼就去 /taskList 下創建本身的臨時時序節點(CreateMode.EPHEMERAL_SEQUENTIAL),當 /taskList 發現本身下面的子節點知足指定個數,就能夠進行下一步按序進行處理了。 |