概述
ZooKeeper是一個分佈式的,開源的分佈式應用程序協調服務,它包含一個簡單的原語集,屬於Apache的頂級項目,能夠基於它實現服務發現,配置維護,集羣管理和分佈式鎖等。node
架構
經過架構圖咱們看到zookeeper主要有以下四種角色:緩存
- Leader:處理讀寫請求,處理與Follower的心跳檢測,並以事務的方式處理與Follower和Observer的數據同步
- Follower:直接處理讀請求,對於寫請求轉發給 Leader,Leader選舉中參與競爭和投票,與Leader維持數據同步
- Observer:直接處理讀請求,對於寫請求轉發給 Leader,Leader選舉中不參與投票,與Leader維持數據同步
- Client:請求發起者
概念
- znode
zk中數據都存儲在znode中,一個znode節點能夠包含子znode同時也能夠包含數據,每一個znode都有一個惟一的訪問路徑。znode主要有以下四種類型:
- PERSISTENT-持久化目錄節點
客戶端與zookeeper斷開鏈接後,該節點依舊存在
- PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點
客戶端與zookeeper斷開鏈接後,該節點依舊存在,只是Zookeeper給該節點名稱進行順序編號
- EPHEMERAL-臨時目錄節點
客戶端與zookeeper斷開鏈接後,該節點被刪除
- EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點
客戶端與zookeeper斷開鏈接後,該節點被刪除,只是Zookeeper給該節點名稱進行順序編號
- session
session是zookeeper中會話的實例載體,一個session則是指代一個客戶端會話。一個會話必須包含如下幾個基本的屬性:
- sessionID : 會話的ID,用來惟一標識一個會話,每一次客戶端創建鏈接的時候,zookeeper服務端都會給其分配一個全局惟一的sessionID
- timeOut:一次會話的超時時間,客戶端在構造zookeeper實例的時候,會配置一個sessionTimeOut參數用於指定會話的超時的時間。zookeeper服務端會按照鏈接的客戶端發來的timeOut參數來計算並肯定超時的時間
- tickTime:下一次會話超時的時間點,爲了方便zookeeper對會話進行所謂的分桶策略進行管理,同時也能夠實現高效的對會話的一個檢查和清理。tickTime是一個13位的Long類型的數值,通常狀況下這個值接近timeOut,可是並不徹底相等
- isCloseing:用來標記當前會話是否已經處於被關閉的狀態。若是服務端檢測到當前會話的超時時間已經到了,就會將isCloseing屬性標記爲已經關閉,這樣之後即便再有這個會話的請求訪問也不會被處理
- watch
用戶能夠對一個znode設置watch,當這個znode發生了變化時,例如建立、刪除、數據變動、添加或移除子節點,watch API就會發出通知。可是,zookeeper的 watch有一個缺點,就是這個watch只能被觸發一次,一旦發出了通知,若是還想對這個節點繼續watch,用戶須要從新設置watch。
- zxid
leader 服務器在接收到事務請求後,會爲每一個事務請求生成對應的 proposal 來進行廣播,而且在廣播事務 proposal 以前,leader 服務器會首先爲這個事務 proposal 分配一個全局單調遞增的惟一 ID ,咱們稱之爲zxid。zxid就是zk中的事務編號,是一個8字節的整型數字,一共有64位長度,前32位用來記錄epoch,後32位就是用來計數。每一次寫請求都會增長後32位,每一次leader選舉會增長前32位,每次增長都是+1。
- myid
啓動配置zoo.cfg中有一項 dataDir 指定了數據存放的路徑,在此路徑下新建一個文本文件,命名爲myid, 文本內容就是一個數字,這個數字就是當前節點的myid,用來惟一標識一個節點。
- 節點的狀態
在zab協議中,是經過自身的狀態來區分本身的角色的。在組成zab協議的全部進程啓動的時候,初始化狀態都是 LOOKING 狀態,此時進程組中不存在leader,選舉以後纔有,在進行選舉成功後,就進入消息廣播模式,此時 zookeeper 集羣中的角色狀態就再也不是 LOOKING 狀態。在運行期間各個進程可能出現如下三種狀態之一:
- LOOING:處在這個狀態時,會進入 Leader 選舉狀態
- FOLLOWER:Follower 服務器和 Leader 服務器保持同步時的狀態
- LEADING:Leader 服務器做爲主進程領導者的狀態
- prososal
leader服務器將客戶端事務請求轉化成一個事務prososal 核心zab協議
zookeeper分佈式服務可以知足CAP理論中的CP,即能保證一致性和分區容忍性,可是不是保證可用性。像在leader選舉的過程當中,服務是不可用的。而zookeeper是採用zab(Zookeeper Atomic Broadcast)原子消息廣播協議來保證CP。
zab在工做的過程當中,會有兩種模式的切換:崩潰恢復模式和消息廣播模式。服務器
- 在進入崩潰恢復模式時 zookeeper集羣會進行 leader 選舉,通常有兩種狀況會發生選舉:
- 當服務器啓動時期會進行 Leader 選舉。
- 當服務器運行期 Leader 服務器的出現網絡中斷、崩潰退出、重啓等異常狀況,或者當集羣中半數的服務器與該 Leader 服務器沒法通訊時,進入崩潰恢復模式,開始 Leader 選舉。
- 選舉出 Leader 服務器後,會進入消息廣播模式,開始接收處理客戶端的請求。
恢復模式
崩潰恢復模式下 leader 選舉的過程細節以下:網絡
- 檢測節點處於 LOOKING 階段,開始選舉 leader
發起投票時有兩種狀況:
- 在服務啓動的初始階段,每一個服務器都會投票給本身以(myid,zxid)的信息形式發送,那初始階段沒有 zxid 值,就會發送(myid,0)
- 在服務器運行期間,每一個服務器上的 zxid 都有值,且 zxid 都不相同,因此就正常發送(myid,zxid)
- 各節點收到信息後將收到的(myid,zxid)和本身的比較。會比較epoch、寫請求操做數、myid三個字段,依次比較誰大誰就更有資格成爲leader
- 而後判斷是否有半數的機器投票選出 leader,若是否,在進入新一輪投票,直到選出
- 選出 leader 後,其餘節點就變成 follower 角色,並向 leader 發送本身服務器的最大 zxid ,leader 服務器收到後會和本身本地的提議緩存隊列進行比較,判斷使用那種策略進行同步
- 當同步完成,集羣就能夠正常的處理請求了,就進入消息廣播模式了
消息廣播模式
主要過程以下:session
- leader 服務器接收到請求後在進行廣播事務 proposal 以前會爲這個事務分配一個 ZXID,再進行廣播。
- leader 服務器會爲每一個 follower 服務器都各自分配一個單獨的隊列,而後將須要廣播的事務 proposal 依次放入這些隊列中去,並根據 FIFO 策略進行消息的發送。
- 每一個follower 服務器在接收到後都會將其以事務日誌的形式寫入到本地磁盤中,而且在成功寫入後返回leader 服務器一個 ACK 響應。
- 當有超過半數的服務器 ACK 響應後,leader 就會廣播一個 commit 消息給全部的 follower 服務器,follower 接收到後就完成對事務的提交操做。
應用場景
發佈訂閱
做爲配置中心,來存放服務的配置架構
命名服務
命名服務是指經過指定的名字來獲取資源或者服務的地址,提供者的信息。簡單來講使用Zookeeper作命名服務就是用路徑做爲名字,路徑上的數據就是其名字指向的實體,例如url地址。併發
集羣管理
集羣中的全部節點都註冊到zk中,並添加watch機制。可以實現集羣節點數量,在線狀態,上下線狀態等的自動發現。異步
分佈式通知/協調
ZooKeeper 中特有 watcher 註冊與異步通知機制,可以很好的實現分佈式環境下不一樣系統之間的通知與協調,實現對數據變動的實時處理。socket
master選舉
利用zooKeeper的一致性,可以保證在分佈式高併發狀況下節點建立的全局惟一性,即:同時有多個客戶端請求建立 /currentMaster 節點,最終必定只有一個客戶端請求可以建立成功。利用這個特性,就能很輕易的在分佈式環境中進行集羣選取了。分佈式
分佈式鎖
鎖服務能夠分爲兩類,一個是保持獨佔,另外一個是控制時序。
- 獨佔
全部客戶端都去建立 /distribute_lock 節點,最終成功建立的那個客戶端也即擁有了這把鎖。
- 控制時序
/distribute_lock節點已預先存在,客戶端在它下面建立臨時有序節點(這個能夠經過節點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。zk的父節點(/distribute_lock)維持一份 sequence,保證子節點建立的時序性,從而也造成了每一個客戶端的全局時序。 分佈式隊列
隊列方面,簡單地講有兩種,一種是常規的先進先出隊列,另外一種是要等到隊列成員聚齊以後的才統一按序執行。對於第一種先迚先出隊列,和分佈式鎖服務中的控制時序場景基本原理一致,這裏再也不贅述。
第二種隊列實際上是在 FIFO 隊列的基礎上做了一個加強。一般能夠在 /queue 這個 znode 下預先創建一個/queue/num 節點,而且賦值爲 n(或者直接給/queue 賦值 n),表示隊列大小,以後每次有隊列成員加入後,就判斷下是否已經到達隊列大小,決定是否能夠開始執行了。這種用法的典型場景是,分佈式環境中,一個大任務 Task A,須要在不少子任務完成(或條件就緒)狀況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那麼就去 /taskList 下創建本身的臨時時序節點(CreateMode.EPHEMERAL_SEQUENTIAL),當 /taskList 發現本身下面的子節點知足指定個數,就能夠進行下一步按序進行處理了。
優缺點
優勢
- 高可靠
- 應用普遍,比較成熟
- 支持監聽事件
- API簡單
缺點
- 對於每一個 watch 請求,zookeeper 都會打開一個新的 socket 鏈接,這樣 zookeeper 就須要實時管理不少 socket 鏈接,比較複雜
總結
zookeeper是一款成熟的協調服務,應用普遍。