ZooKeeper是一個典型的發佈/訂閱模式的分佈式數據管理與協調框架,開發人員可使用它來進行分佈式數據的發佈與訂閱。另外一方面,經過對ZooKeeper中豐富的數據節點類型進行交叉使用,配合Watcher事件通知機制,能夠很是方便的構建一系列分佈式應用中都會涉及的核心功能,如數據發佈/訂閱、負載均衡、命名服務、分佈式協調/通知、集羣管理、Master選舉、分佈式鎖和分佈式隊列等。算法
數據發佈/訂閱(Publish/Subscribe)系統,即所謂的配置中心,顧名思義就是發佈者jiang將數據發佈到ZooKeeper的一個或一系列節點上,供訂閱者進行數據訂閱,進而達到動態獲取數據的目的,實現配置信息的集中式管理和數據的動態更新。數據庫
發佈/訂閱系統通常有兩種設計模式,分別是推(Push)模式和拉(Pull)模式。編程
服務端主動將數據更新發送給全部訂閱的客戶端。設計模式
客戶端經過採用定時輪詢拉取。服務器
ZooKeeper採用的是推拉相結合的方式:客戶端向服務端註冊本身須要關注的節點,一旦該節點的數據發生變動,那麼服務端就會向相應的客戶端發送Watcher事件通知,客戶端接收到這個消息通知以後,須要主動到服務端獲取最新的數據。網絡
根據維基百科的定義,負載均衡(Load Balance)是一種至關常見的計算機網絡技術,用來對多個計算機(計算機集羣)、網絡鏈接、CPU、硬盤驅動器或其餘資源進行分配負載,以達到優化資源使用、最大化吞吐率、最小化響應時間和避免過載的目的。一般,負載均衡能夠分爲硬件和軟件負載均衡兩類。負載均衡
命名服務(Name Service)也是分佈式系統中比較常見的一類場景。在《Java網絡高級編程》一書中提到,命名服務是分佈式系統最基本的公共服務之一。在分佈式系統中,被命名的實體一般是集羣中的機器、提供的服務地址或遠程對象等--這些咱們均可以統稱他們爲名字,其中比較常見的就是一些分佈式服務框架(RPC、RMI)中的服務地址列表,經過使用命名服務,客戶端應用可以根據指定名字來獲取資源的實體、服務地址和提供者信息等。框架
Java語言中的JNDI即是一種典型的命名服務。JNDI是Java命名和目錄接口(Java Naming and Directory Interface)的縮寫,是J2EE體系中重要的規範之一,標準的J2EE容器都提供了對JNDI規範的實現。所以,在實際開發中,開發人員經常使用應用服務器自帶的JNDI實現來完成數據源的配置與管理--使用JNDI方式後,開發人員能夠徹底不須要關心與數據庫相關的任何信息,包括數據庫類型、JDBC驅動類型以及數據庫帳戶等。異步
ZooKeeper提供的命名服務功能與JNDI技術有相似的地方,都可以幫助應用系統經過一個資源引用的方式來實現對資源的定位與使用。另外,廣義上命名服務的資源定位都不是真正意義的實體資源--在分佈式環境中,上層應用僅僅須要一個全局惟一的名字,相似於數據庫的惟一主鍵。下面咱們看看如何使用ZooKeeper來實現一套分佈式全局惟一ID的分配機制。分佈式
所謂ID,就是一個能惟一標識某個對象的標識符。一提及全局惟一ID,相信讀者都會聯想到UUID。UUID是通用惟一標識碼(Universally Unique Identifier)的簡稱,是一種在分佈式系統中普遍使用的用於惟一標識元素的標準,最典型的實現是GUID(Globally Unique Identifier,全局惟一標識符),主流ORM框架Hibernate有對UUID的直接支持。
一個標準的UUID是一個包含32位字符和4各短線的字符串。他的優點天然沒必要多說,咱們來看看他的缺陷。
和數據庫中的INT類型相比,存儲一個UUID須要花費更多的空間。
根據字面徹底看不出任何含義,這會大大影響問題排查和開發調試的效率。
接下來咱們來說解使用ZooKeeper生成惟一ID的基本步驟。
分佈式協調/通知是將不一樣的分佈式組件有機結合起來的關鍵所在。對於一個在多臺機器上部署運行的應用而言,一般須要一個協調者(Coordinator)來控制整個系統的運行流程,例如分佈式事務的處理、機器間的相互協調等。同時,引入這樣一個協調者,便於將分佈式協調的職責從應用中分離出來,從而大大減小系統之家的耦合性,並且可以顯著提升系統的可擴展性。
ZooKeeper中特有的Watcher註冊於異步通知機制,可以很好地實現分佈式環境下不一樣機器,甚至是不一樣系統之間的協調與通知,從而實現對數據變動的實時處理。基於ZooKeeper實現分佈式協調與通知功能,一般的作法是不一樣的客戶端都對ZooKeeper上同一數據節點進行Watcher註冊,監聽數據節點的變化(包括數據節點自己及其子節點),若是數據節點發生變化,那麼全部訂閱的客戶端都能接收到相應的Watcher通知,並做出相應的處理。
機器間的心跳檢測機制是指在分佈式環境中,不一樣機器之間須要檢測到彼此是否在正常運行。在傳統的開發中,咱們一般是經過主機之間是否能夠相互PING通來判斷,更復雜一點的話,則會經過在機器之間創建長鏈接,經過TCP鏈接固有的心跳檢測機制來實現上層機器的心跳檢測。
下面看看如何使用ZooKeeper來實現分佈式機器間的心跳檢測。基於ZooKeeper的臨時節點特性,可讓不一樣的機器都在ZooKeeper的一個指定節點下建立臨時子節點,不一樣的機器之間能夠根據這個臨時節點來判斷對應的客戶端機器是否存活。經過這種方式,檢測系統和被檢測系統間並不須要直接相關聯,而是經過ZooKeeper上的某個節點進行關聯,大大減小了系統耦合。
後臺管理人員操做控制檯,實際上修改ZooKeeper某些節點的數據,而後ZooKeeper把這些數據變動以事件通知的形式發送給了對應的訂閱客戶端。
在Hadoop中,ZooKeeper主要用於實現HA(High Availability),這部分邏輯主要集中在Hadoop Common的HA模塊中,HDFS的NameNode與YARN的ResouceManager都是基於此HA模塊來實現本身的HA功能的。同時,在YARN中又特別提供了ZooKeeper來存儲應用的運行狀態。
HBase,全程Hadoop Database,是Google Bigtable的開源實現,是一個基於Hadoop文件系統設計的面向海量數據的高可靠性、高性能、面向列、可伸縮的分佈式存儲系統,利用HBase技術能夠在廉價的PC服務器上搭建起大規模結構化的存儲集羣。
HBase在實現上嚴格遵照了Google BigTable論文的設計思想。BigTable使用Chubby來負責分佈式狀態的協調,這是Google實現的一種基於Paxos算法的分佈式鎖服務,而HBase則採用了開源的ZooKeeper服務來完成對整個系統的分佈式協調工做。
Kafka是一個吞吐量極高的分佈式消息系統,其總體設計師典型的發佈與訂閱模式系統。在Kafka集羣中,沒有「中心主節點」的概念,集羣中全部的服務器都是對等的,所以能夠在不作任何配置更改的狀況下實現服務器的添加和刪除,一樣,消息的生產者和消費者也能作到隨意重啓和機器的上下線。在Kafka的設計中,選擇使用ZooKeeper來進行全部Broker的管理。
Kafka使用ZooKeeper做爲其分佈式協調框架,很好地將消息生成、消息存儲和消息消費有機結合起來,同時藉助ZooKeeper,Kafka能在保持包括生產者、消費者和Broker在內的全部組件無狀態的狀況下,創建起生產者和消費者之間的訂閱關係,並實現了生產者和消費者的負載均衡。