ZooKeeper是一個開源的分佈式協調服務(a service for coordinating processes of distributed applications),由雅虎公司建立,是Google Chubby的開源實現(Google Chubby是有名的分佈式鎖服務,GFS和Big Table等大型系統都用它來解決分佈式協調、Master選舉等一系列與分佈式鎖服務相關的問題)。分佈式程序能夠基於ZooKeeper實現負載均衡,命名服務,分佈式鎖等功能。ZooKeeper將全量數據都存在內存中,實現提升服務器吞吐、減小延遲的目的。node
上面的英文說的足夠簡而意賅了,a service for coordinating processes of distributed applications。是爲了協調分佈式應用的,到底解決什麼樣的問題呢。相信你們的Java基礎都不錯,我的以爲仍是拿鎖舉例子比較好理解,在單機式中,咱們想保證多個線程爭搶,最後只有一個線程爭搶到執行權(鎖)並執行你想要讓他作的業務代碼,最簡單的方式,能夠用:算法
synchronized (obj){
//業務邏輯
}
那麼在分佈式的狀況下呢?怎麼保證,同一個服務部署在不一樣機器上實現如上目標呢?那麼這就是分佈式協調服務要乾的事情。分佈式協調遠遠比同一個進程裏的協調複雜得多,因此相似Zookeeper這類分佈式協調服務就應運而生。在解決分佈式數據一致性上,除了ZooKeeper,目前沒有一個成熟穩定且被大規模應用的開源方案。且愈來愈多的大型分佈式項目如HBase、Storm都已經使用ZooKeeper做爲其核心組件,用於分佈式協調。數據庫
ZooKeeper能夠保證以下分佈式一致性特性:安全
在立項初期,考慮到以前內部不少項目都是使用動物的名字來命名的(例如著名的Pig項目),雅虎的工程師但願給這個項目也取一個動物的名字。時任研究院的首席科學家 Raghu Ramakrishnan 開玩笑地說:「在這樣下去,咱們這兒就變成動物園了!」此話一出,你們紛紛表示就叫動物園管理員吧,由於各個以動物命名的分佈式組件放在一塊兒,雅虎的整個分佈式系統看上去就像一個大型的動物園了。而 Zookeeper 正好要用來進行分佈式環境的協調,因而,Zookeeper 的名字也就由此誕生了。服務器
在ZooKeeper中,集羣有3個角色:Leader、Follower和Observer三種角色。數據結構
Leader:ZooKeeper集羣中全部機器經過選舉過程選定集羣中的一臺機器爲Leader,事務請求惟一調度者和處理者,保證集羣事務處理的順序性app
Follower:爲客戶端提供讀服務、參與Leader選舉過程、參與寫操做的「過半寫成功」策略,收到寫事務請求直接轉發給Leader負載均衡
Observer:爲客戶端提供讀服務,在不影響集羣事務處理能力的前提下提高集羣的非事務處理能力框架
Session是ZooKeeper中的會話實體,表明了一個客戶端會話,一個客戶端鏈接指客戶端和服務器之間的一個TCP長鏈接。經過這個鏈接,客戶端可以作如下事情分佈式
- 向ZooKeeper服務器發送請求並接收響應
- 心跳檢測
- 接收來自服務器的Watch事件
數據節點(Znode)是指數據模型中的數據單元,ZooKeeper內存數據存儲的核心是DataTree,是一個樹的數據結構,表明了內存中的一份完整的數據,由斜槓"/"進行分割的路徑,就是一個Znode,每一個Znode都保存本身的數據內容
每一個Znode都有三種類型的版本信息,對節點數據變更會引發版本號變化
version:當前數據節點數據內容的版本號
cversion:當前數據節點子節點的版本號
aversion:當前數據節點ACL變動版本號
事件監聽器(Watcher)是ZooKeeper很是重要的特性,咱們能夠在節點上註冊Watcher,而且在一些特性事件觸發時候,服務器將事件通知到客戶端上
ZooKeeper使用ACL(Access Control Lists)權限控制機制保證數據安全,有5個權限:
CREATE:建立子節點的權限
READ:獲取節點數據和子節點列表的權限
WRITE:更新節點數據的權限
DELETE:刪除子節點的權限
ADMIN:設置節點ACL的權限
咱們能夠回頭看最上面的圖,Hbase,Hadoop,Kafka等已經被普遍應用在愈來愈多的大型分佈式系統中,用來解決諸如配置管理,分佈式通知/協調、集羣管理和Master選舉等一系列分佈式問題
ZooKeeper在阿里的實踐有Dubbo,消息中間件Metamorphosis,分佈式數據庫同步系統Otter,實時計算引擎Jstorm等
能夠這麼說,No ZAB,No ZooKeeper。ZAB協議是整個ZooKeeper框架的核心所在。
ZooKeeper是一個高可用的分佈式數據管理與協調框架。基於對ZAB算法的實現,ZooKeeper成爲了解決分佈式環境中數據的一致性問題的利器。ZAB協議的全稱是ZooKeeper Atomic Broadcast(ZooKeeper原子消息廣播協議)。ZAB協議是一種特別爲ZooKeeper設計的崩潰可恢復的原子消息廣播算法。
全部事務請求必須由惟一的Leader服務器來協調處理,其餘服務器則成爲Follower服務器。Leader服務器負責將事務請求轉換成一個提議,並將該提議分發到集羣中的全部Follower服務器,以後Leader服務器須要等待全部Follower的響應,一旦超過半數的Follower服務器進行了正確的反饋後(不須要等待集羣中全部的Follower服務器都反饋響應),那麼Leader就會再次向全部Follower服務器分發Commit消息,要求對前一個提議進行提交。
首先先來看一下選舉算法出現的一些專有術語
SID是一個數據,標識一臺ZooKeeper集羣中的機器,SID不能重複,和myid值同樣。(集羣的配置文件中,server.id=host:port:port,這裏的id就是myid,咱們還須要在dataDir參數的目錄建立myid文件,就是這裏的id)
ZXID是一個事務ID,標記惟一一次服務器狀態的變動,某一時刻,集羣中的每臺機器的ZXID不必定都一致,以前已經說過了。它是一個64位的數字,低32位能夠看做遞增計數器,高32位表明Leader週期epoch的編號
咱們能夠看下Vote的數據結構:
接下來咱們來解釋一下每一個字段的意思:
id:被選舉的Leader的SID值
zxid:被選舉的Leader的事務ID
electionEpoch:邏輯時鐘
peerEpoch:被選舉的Leader的epoch
state:當前服務器的狀態
quorum=(n/2+1),假如集羣總數是3,那麼quorum就是2
階段一就是Leader選舉過程(服務器啓動期間或者服務器運行期間),服務器的狀態進入LOCKING狀態。進入選舉Leader流程。
不要死記硬背具體規則,總結簡單來講,哪臺服務器上的數據較新,也就是它的ZXID越大,那麼越有可能成爲Leader。若是幾個服務器具備相同的ZXID,那麼SID較大的服務器成爲Leader。
規則1:若是收到投票的ZXID大於自身的ZXID,就承認收到的投票再次投出去
規則2:若是收到投票的ZXID小於自身的ZXID,則堅持本身的投票不作任何變動
規則3:若是收到投票的ZXID等於自身的ZXID,則對比二者SID,若是收到投票的SID大於自身的SID則承認收到的投票再次投出去
規則4:若是收到投票的ZXID等於自身的ZXID,而且收到投票的SID小於自身SID則堅持本身的投票不作任何變動
接下來舉個例子來講明選舉的過程:
過程A:咱們假設ZooKeeper由5臺機器組成,SID分別爲1,2,3,4,5。ZXID分別爲9,9,9,8,8。此時SID爲2的機器是Leader服務器,某一時刻SID爲1和2的機器出現故障,所以集羣開始進行Leader選舉,state切換到LOCKING狀態。
過程B:第一次投票,每臺機器都選本身做爲被選舉的對象來進行投票,因此SID爲3,4,5的投票狀況爲(這裏Vote作簡化,只有SID和ZXID):(3,9),(4,8),(5,8)。
過程C:Server3收到(4,8)和(5,8)。根據規則2,不作任何投票的變動。
Server4收到(3,9)和(5,8)。根據規則1,須要變動投票爲(3,9)。
Server5一樣的變動投票爲(3,9)。
過程D:第二輪投票後,Server3收到超過一半的票數,成爲Leader
選舉完成後,Leader服務器會爲每個Follower服務器都準備一個隊列,並將那些沒有被各Follower服務器同步的事務以Proposal消息的形式逐個發送給Follower服務器,而後在提議消息以後緊接發送一個Commit消息,表示該事務被提交,等到Follower服務器都將未同步的事務從Leader服務器同步過來併成功應用到本地數據庫後,Leader服務器會將該Follower服務器加入真正可用的Follower列表中
Leader服務器會給每一個Follower分配一個FIFO的隊列來分送事務,Follower服務器收到事務Proposal以後以事務日誌的形式寫入本地磁盤,寫入成功會給Leader服務器回覆一個ACK。
當Leader服務器收到過半的ACK響應則廣播發送Commit消息給全部Follower,而後全部服務器完成對事務的提交。