Zookeeper是分佈式一致性問題的工業解決方案,是Apache Hadoop下解決分佈式一致性的一個組件,後被分離出來成爲Apache的頂級項目。java
工程來源:是雅虎公司內部項目,聽說雅虎內部不少項目都是以動物命名,這個動物管理員的名字起的非常形象。node
被開源出來後獲得開源社區的快速推動,服務端Java語言實現,棒,git有3000+的star:linux
https://github.com/apache/zookeepergit
zookeeper集羣結構github
集羣的角色,比較典型的是Master/Slave(主備模式),zk中的概念跟這個不同,包含Leader、Follower、Observer三個角色,leader提供讀和寫的能力,follower只對外提供讀的能力。web
會話(session)redis
客戶端跟服務端交互,是先與服務端創建一個TCP長鏈接,會話開始,經過心跳檢測與服務端保持會話有效,向服務端發送請求和接收響應。算法
zk將全部的數據都加載在內存一份,同時有事務日誌文件(持久化文件),服務端會定時dump快照數據,重啓機器的時候會根據快照和事務日誌恢復內存數據庫的數據,這跟redis的AOF和RDB概念相似。數據庫
zookeeper上的數據結構apache
zk上的數據的結構跟linux文件系統很像,是個樹狀結構
節點(node)上的信息字段
節點類型包括:
其中臨時節點特性就是建立它的主體消失後,它就跟着消失了。後續的應用就是利用的節點的特性實現的。
事件監聽器(watcher)
這個應該是zookeeper最重要的概念之一了,zk容許用戶在特定的節點(znode)上註冊watcher,而且在特定事件觸發的時候,zk服務端會將事件通知到感興趣的客戶端上。
僞集羣的搭建:
zoo.cfg 配置文件
啓動成功後,命令行鏈接zk,能夠用指令作些增刪改查的操做
telnet 127.0.0.1 2181
stat:能夠看集羣的狀態信息
stat信息
每次事務操做,會在dataDir的目錄下的事務日誌,是序列化的二進制文件,zookeeper提供了查看事務日誌的工具類LogFormatter
LogFormatter轉換後的事務日誌文件
Java客戶端使用
cruator客戶端例子
zookeeper應用場景
利用zookeeper的特性,能夠比較方便的構建分佈式應用會涉及的核心功能,好比:配置中心、命名服務、分佈式協調/通知、集羣的管理、master選舉、分佈式鎖等
如下應用基本基於zookeeper的兩大特性實現
--配置中心:
配置中心
zookeeper利用推拉結合的方式,客戶端向服務端註冊本身須要關注的節點,一旦該數據發生變動,那麼服務器就會向相應的客戶端發送watcher時間通知。
客戶收到這個消息通知以後,再主動到服務端獲取最新的數據。即回調的event中包含具體的數據。
這個應用的的業務員特色:
--命名服務
利用zookeeper的順序節點,樹形結構的數據特色,實現命名服務:
這樣RPC的客戶端只須要傳對應的服務名字,和接口,就能找到對應的服務。
使用zookeeper實現:不一樣的業務下建立一個節點,具體的節點下用zk的順序節點(sequent)生成id當作這個業務的全局惟一id使用
--分佈式通知/協調
ZooKeeper中特有watcher註冊與異步通知機制,可以很好的實現分佈式環境下不一樣系統之間的通知與協調,實現對數據變動的實時處理。
使用方法一般是不一樣系統都對ZK上同一個znode進行註冊,監聽znode的變化(包括znode自己內容及子節點的),其中一個系統update了znode,那麼另外一個系統可以收到通知,並做出相應處理。
應用:
心跳檢測機制:傳統的方式是ping,複雜的話是創建長鏈接檢測系統和被檢測系統之間並不直接關聯起來,而是經過zookeeper上某個節點關聯,大大減小系統耦合
系統調度模式:某系統由控制檯和推送系統兩部分組成,控制檯的職責是控制推送系統進行相應的推送工做。
管理人員在控制檯做的一些操做,其實是修改了ZK上某些節點的狀態,而ZK就把這些變化通知給他們註冊Watcher的客戶端,即推送系統。因而,做出相應的推送任務
做彙報模式:一些相似於任務分發系統,子任務啓動後,到ZK來註冊一個臨時節點,而且定時將本身的進度進行彙報(將進度寫回這個臨時節點)
總之,使用zookeeper來進行分佈式通知和協調可以大大下降系統之間的耦合。
--分佈式鎖
這個應用主要得益於ZooKeeper爲咱們保證了數據的強一致性
即用戶只要徹底相信每時每刻,zk集羣中任意節點(一個zk server)上的相同znode的數據是必定是相同的。
一個節點要麼建立成功,要麼失敗,而且只由一個客戶端建立。
獨佔鎖:
保持獨佔,就是全部試圖來獲取這個鎖的客戶端,最終只有一個能夠成功得到這把鎖。
一般的作法是把ZK上的一個znode看做是一把鎖,經過create znode的方式來實現。全部客戶端都去建立/distribute_lock節點,最終成功建立的那個客戶端也即擁有了這把鎖。
共享時序控制鎖:
Zookeeper很容易實現這個功能,實現方式是須要得到鎖的Server,建立一個EPHEMERAL_SEQUENTIAL目錄節點。
而後調用getChildren方法獲取當前的目錄節點列表中最小的目錄節點是否是就是本身建立的目錄節點。
若是正是本身建立的,那麼它就得到了這個鎖,若是不是,那麼它就調用exists(String path, boolean watch)方法,並監控Zookeeper上目錄節點列表的變化,一直到本身建立的節點是列表中最小編號的目錄節點,從而得到鎖。
釋放鎖很簡單,只要刪除前面它本身所建立的目錄節點就好了。
--master選舉
master選舉應用圖
有個容易理解的方案,依靠關係型數據庫主鍵的特性,集羣的機器同時往一張表裏插入數據,數據庫會自動進行主鍵衝突檢查,能夠選擇插入成功的客戶端做爲master
這種方式存在一個問題就是,master機器掛了,沒有人通知
zk實現能夠方便作到這一點:zk的建立節點api接口,具備強一致性,可以保證客戶端併發建立的時候,最終必定只有一個客戶端建立成功。
--集羣管理
應用舉例:集羣機器存活性監控系統,例如:
監控系統在/clusterServers節點註冊一個watcher監聽,那麼但凡進行動態添加機器的操做,就在/clusterServers下建立一個臨時節點, /clusterServers/ip。
這樣監控系統就可以實時的檢測到機器的變更,經過getChild方法獲取全部的臨時節點,來判斷增長的機器。
當有機器down調或者手動下線,相應臨時節點會消失,監控系統也會接收到,來處理監控服務的具體業務
具體服務器部署agent實現
zookeeper的HA設計實現
以上說了那麼多犀利實用的應用場景,它們依賴zookeeper,說明這些應用服務的高可用性依賴的zookeeper自己的HA。
zk的選舉算法
算法協議zab協議,「少數服從多數」協議一種
3.4.0版本以後Zookeeper只保留了TCP版本的FastLeaderElection選舉算法
分析選舉算法前,先熟悉瞭解下zk的一些術語定義解釋:
集羣數量是4,quorum=2,集羣數量是5,quorum=3
當哪些狀況發生時會出發leader從新選舉呢?
當zk的一臺服務器出現如下兩種狀況的時候,會進入leader選舉流程
對於第一種狀況,即已經存在一臺leader服務器,當改機器試圖去選舉leader的時候,會被告知當前服務器的leader信息,對於該機器僅僅須要和leader創建鏈接,並進行狀態同步便可
主要看下第二種狀況:
有兩種狀況致使集羣不存在leader,一個是集羣剛啓動初始化的時候,另外一種狀況是運行期間leader所在服務器掛了。
不管哪一種狀況集羣全部集羣都處在一個找leader的狀態,稱做Looking狀態,開始想其餘機器發送消息投票
開始leader選舉投票的協議規則是怎樣呢?
5臺機器宕機兩臺後,leader選舉的過程圖示
所以,一個錯誤的認識,爲了使zookeeper集羣能順利的選出leader,必須將zookeeper集羣的服務器數部署爲奇數。
從上邊例子能看出來部署任意臺機器都可以正常選舉運行。部署奇數臺是官方給的建議,由於奇數和奇數+1的容災能力是同樣的。好比:
5臺服務器,可以對2臺機器掛掉的狀況進程容災
6臺服務器,可以對2臺機器掛掉的狀況進程容災,若是掛掉3臺,剩下的機器就沒法實現過半了。