目錄java
Zookeeper是大數據生態圈中的重要組件,若是你作過相關開發的話,應該常常能看到它的身影。其由雅虎開源併成爲Apache的頂級項目。用一句話對其進行定義就是:它是一套高吞吐的分佈式協調系統。從中咱們能夠知道Zookeeper至少具備如下特色:node
縱軸爲每秒響應的客戶端請求數,橫軸爲讀請求所佔百分比。從圖中能夠清晰的看到,隨着讀請求所佔百分比的提升,Zookeeper的QPS也不斷提升。
Zookeeper具備高吞吐特性的主要緣由有如下幾點:算法
1.Zookeeper集羣的任意一個服務端節點均可以直接響應客戶端的讀請求(寫請求會不同些,下面會詳談),而且能夠經過增長節點進行橫向擴展。這是其吞吐量高的主要緣由服務器
2.Zookeeper將全量數據存儲於內存中,從內存中讀取數據不須要進行磁盤IO,速度要快得多。併發
3.Zookeeper放鬆了對分佈式數據的強一致性要求,即不保證數據實時一致,容許分佈式數據通過一個時間窗口達到最終一致,這也在必定程度上提升了其吞吐量。負載均衡
而寫請求,或者說事務請求,由於要進行不一樣服務器結點間狀態的同步,必定程度上會影響其吞吐量。故而簡單的增長Zookeeper的服務器節點數量,對其吞吐量的提高並不必定能起到正面效果。服務器節點增長,有利於提高讀請求的吞吐量,但會延長服務器節點數據的同步時間,必須視具體狀況在這二者之間取得一個平衡。分佈式
在Zookeeper集羣中,分別有Leader,Follower和Observer三種類型的服務器角色。性能
Leader
Leader服務器在整個正常運行期間有且僅有一臺,集羣會經過選舉的方式選舉出Leader服務器,由它同統一處理集羣的事務性請求以及集羣內各服務器的調度。大數據
Observer
Observer是弱化版的Follower。其像Follower同樣可以處理非事務也就是讀請求,並轉發事務請求給Leader服務器,可是其不參與任何形式的投票,不論是Leader選舉投票仍是事務請求Proposal的投票。引入這個角色主要是爲了在不影響集羣事務處理能力的前提下提高集羣的非事務處理的吞吐量。設計
Zookeeper將數據存儲於內存中,具體而言,Znode是存儲數據的最小單元。而Znode被以層次化的結構進行組織,形容一棵樹。其對外提供的視圖相似於Unix文件系統。樹的根Znode節點至關於Unix文件系統的根路徑。正如Unix中目錄下能夠有子目錄同樣,Znode結點下也能夠掛載子結點,最終造成以下所示結構。
以文件系統進行類比的話,Znode自然具備目錄和文件兩重屬性:即Znode既能夠當作文件往裏面寫東西,又能夠當作目錄在下面掛載其餘Znode。固然,因爲Znode具備不一樣的類型,後半部分並不徹底準確。
Znode按其生命週期的長短能夠分爲持久結點(PERSISTENT)和臨時結點(EPHEMERAL);在建立時還可選擇是否由Zookeeper服務端在其路徑後添加一串序號用來區分同一個父結點下多個結點建立的前後順序。
通過組合就有如下4種Znode結點類型
1.持久結點(PERSISTENT)
最多見的Znode類型,一旦建立將在一直存在於服務端,除非客戶端經過刪除操做進行刪除。持久結點下能夠建立子結點。
2.持久順序結點(PERSISTENT_SEQUENTIAL)
在具備持久結點基本特性的基礎上,會經過在結點路徑後綴一串序號來區分多個子結點建立的前後順序。這工做由Zookeeper服務端自動給咱們作,只要在建立Znode時指定結點類型爲該類型。
3.臨時結點(EPHEMERAL)
臨時結點的生命週期和客戶端會話保持一致。客戶端段會話存在的話臨時結點也存在,客戶端會話斷開則臨時結點會自動被服務端刪除。臨時結點下不能建立子結點。
4.臨時順序結點(EPHEMERAL_SEQUENTIAL)
具備臨時結點的基本特性,又有順序性。
Znode結構主要由存儲於其中的數據信息和狀態信息兩部分構成,經過get 命令獲取一個Znode結點的信息以下
第一行存儲的是ZNode的數據信息,從cZxid開始就是Znode的狀態信息
Znode的狀態信息比較多,挑幾個比較重要的講
czxid:
即Created ZXID,表示建立該Znode結點的事務ID
mzxid:
即Modified ZXID,表示最後一次更新該結點的事務ID
version
該Znode結點的版本號。每一個Znode結點被建立時版本號都爲0,每更新一次都會致使版本號加1,即便更新先後Znode存儲的值沒有變化版本號也會加1。version值能夠形象的理解爲Znode結點被更新的次數。Znode狀態信息中的版本號信息,使得服務端能夠對多個客戶端對同一個Znode的更新操做作併發控制。整個過程和java中的CAS有點像,是一種樂觀鎖的併發控制策略,而version值起到了衝突檢測的功能。客戶端拿到Znode的version信息,並在更新時附上這個version信息,服務端在更新Znode時必須必須比較客戶端的version和Znode的實際version,只有這兩個version一致時纔會進行修改。
Zookeeper中能夠經過Watcher來實現事件監聽機制。客戶端能夠向服務端註冊Watcher用以監聽某些事件,一旦該事件發生,服務端即會向客戶端發送一個通知。其主要工做流程以下圖所示
具體而言,Watcher是Zookeeper原生API中提供的事件監聽接口,用戶要實現事件監聽必須實現該接口並重寫process(WatchedEvent event)方法,該方法定義了客戶端在接收到服務端事件通知後的回調邏輯。究竟服務端的什麼事件能夠被監聽?按通知狀態劃分有SyncConnected,Disconnected,Expired,AuthFailed等好多種,這裏主要講下SyncConnected狀態下的幾種事件類型:
Node(-1)
客戶端與服務端成功創建會話
NodeCreated(1)
Watcher監聽的對應Znode被建立
NodeDeleted(2)
Watcher監聽的Znode被刪除
NodeDataChanged(3)
Watcher監聽的Znode的數據內容被改變,注意即便變動先後的數據內容徹底同樣也會觸發該事件,或者理解成該事件的觸發條件是Znode的版本號變動也沒問題
NodeChildrenChanged(4)
Watcher監聽的對應Znode的子結點發生變動
Zookeeper的事件監聽機制有如下特性:
1.當監聽器監聽的事件被觸發,服務端會發送通知給客戶端,但通知信息中不包括事件的具體內容。以監聽ZNode結點數據變化爲例,當Znode的數據被改變,客戶端會收到事件類型爲NodeDataChanged的通知,但該Znode的數據改變成了什麼客戶端沒法從通知中獲取,須要客戶端在收到通知後手動去獲取。
2.Watcher是一次性的。一旦被觸發將會失效。若是須要反覆進行監聽就須要反覆進行註冊。這麼設計是爲了減輕服務端的壓力,可是對開發者而言倒是至關不友好,不過不用着急,能夠經過一些Zookeeper的開源客戶端輕鬆實現對某一事件的永久監聽。
Zookeeper採用ZAB(Zookeeper Atomic Broadcast)協議來保證分佈式數據一致性。ZAB並非一種通用的分佈式一致性算法,而是一種專爲Zookeeper設計的崩潰可恢復的原子消息廣播算法。ZAB協議包括兩種基本模式:崩潰恢復模式和消息廣播模式。崩潰恢復模式主要用來在集羣啓動過程,或者Leader服務器崩潰退出後進行新的Leader服務器的選舉以及數據同步;消息廣播模式主要用來進行事務請求的處理。下面就從這兩個方面來介紹
ZAB協議的核心是定義了對事務請求的處理方式,整個過程能夠歸納以下:
整個過程以下圖所示
當集羣中不存在Leader服務器時集羣會進行Leader服務器的選舉,這一般存在於兩種狀況:1.集羣剛啓動時 2.集羣運行時,但Leader服務器因故退出。集羣中的服務器會向其餘全部的Follower服務器發送消息,這個消息能夠形象化的稱之爲選票,選票主要由兩個信息組成,所推舉的Leader服務器的ID(即配置在myid文件中的數字),以及該服務器的事務ID,事務表示對服務器狀態變動的操做,一個服務器的事務ID越大,則其數據越新。整個過程以下所述:
這樣通過多輪投票後,若是某一臺服務器獲得了超過半數的選票,則其將當前選爲Leader。由以上分析可知,Zookeeper集羣對Leader服務器的選擇具備偏向性,偏向於那些ZXID更大,即數據更新的機器。
整個過程以下圖所示
Zookeeper經過事務日誌和數據快照來避免由於服務器故障致使的數據丟失。