搞懂ZooKeeper到底是做啥的


一.ZooKeeper是啥

ZooKeeper概念

  ZooKeeper是一個開源的分布式協調服務(a service for coordinating processes of distributed applications),由雅虎公司創建,是Google Chubby的開源實現(Google Chubby是有名的分布式鎖服務,GFS和Big Table等大型系統都用它來解決分布式協調、Master選舉等一系列與分布式鎖服務相關的問題)。分布式程序可以基於ZooKeeper實現負載均衡,命名服務,分布式鎖等功能。ZooKeeper將全量數據都存在內存中,實現提高服務器吞吐、減少延遲的目的。

  上面的英文說的足夠簡而意賅了,a service for coordinating processes of distributed applications。是為了協調分布式應用的,到底解決什么樣的問題呢。相信大家的Java基礎都不錯,個人覺得還是拿鎖舉例子比較好理解,在單機式中,我們想保證多個線程爭搶,最后只有一個線程爭搶到執行權(鎖)並執行你想要讓他做的業務代碼,最簡單的方式,可以用:

synchronized (obj){
    //業務邏輯
}

  那么在分布式的情況下呢?怎么保證,同一個服務部署在不同機器上實現如上目標呢?那么這就是分布式協調服務要干的事情。分布式協調遠遠比同一個進程里的協調復雜得多,所以類似Zookeeper這類分布式協調服務就應運而生。在解決分布式數據一致性上,除了ZooKeeper,目前沒有一個成熟穩定且被大規模應用的開源方案。且越來越多的大型分布式項目如HBase、Storm都已經使用ZooKeeper作為其核心組件,用於分布式協調。

  ZooKeeper可以保證如下分布式一致性特性:

  • 順序一致性:從同一客戶端發起的事務請求,最終將會嚴格地按照其發起順序被應用到ZooKeeper中
  • 原子性:要么整個集群所有機器都成功應用了某個事務,要么都沒有應用
  • 單系統鏡像:無論客戶端連接的是哪個ZooKeeper服務器,其看到的服務器數據模型都是一致的(當然,ZooKeeper就是解決分布式數據一致性問題的)
  • 可靠性:一個服務端成功地應用了一個事務,並完成對客戶端的響應,那么該事務所引起的服務端狀態變更將會被一致保留下來,除非有另一個事務又對其進行了變更
  • 實時性:ZooKeeper僅保證在一定時間段內,客戶端最終一定能從服務端上讀取到最新的數據狀態。也就是說比方說一個ZooKeeper集群,有一個時間點,數據在集群中的每個服務器不是一致的,ZooKeeper只保證最終一致性, 但是實時的一致性可以由客戶端調用自己來保證,通過調用sync()方法

ZooKeeper名字誕生

  在立項初期,考慮到之前內部很多項目都是使用動物的名字來命名的(例如著名的Pig項目),雅虎的工程師希望給這個項目也取一個動物的名字。時任研究院的首席科學家 Raghu Ramakrishnan 開玩笑地說:“在這樣下去,我們這兒就變成動物園了!”此話一出,大家紛紛表示就叫動物園管理員吧,因為各個以動物命名的分布式組件放在一起,雅虎的整個分布式系統看上去就像一個大型的動物園了。而 Zookeeper 正好要用來進行分布式環境的協調,於是,Zookeeper 的名字也就由此誕生了。

 

ZooKeeper的核心概念

集群角色

  在ZooKeeper中,集群有3個角色:Leader、Follower和Observer三種角色。

  Leader:ZooKeeper集群中所有機器通過選舉過程選定集群中的一台機器為Leader,事務請求唯一調度者和處理者,保證集群事務處理的順序性

  Follower:為客戶端提供讀服務、參與Leader選舉過程、參與寫操作的“過半寫成功”策略,收到寫事務請求直接轉發給Leader

  Observer:為客戶端提供讀服務,在不影響集群事務處理能力的前提下提升集群的非事務處理能力

 

會話

  Session是ZooKeeper中的會話實體,代表了一個客戶端會話,一個客戶端連接指客戶端和服務器之間的一個TCP長連接。通過這個連接,客戶端能夠做以下事情

  -  向ZooKeeper服務器發送請求並接收響應

  -  心跳檢測

  -  接收來自服務器的Watch事件

數據節點(Znode)

  數據節點(Znode)是指數據模型中的數據單元,ZooKeeper內存數據存儲的核心是DataTree,是一個樹的數據結構,代表了內存中的一份完整的數據,由斜杠"/"進行分割的路徑,就是一個Znode,每個Znode都保存自己的數據內容

版本

  每個Znode都有三種類型的版本信息,對節點數據變動會引起版本號變化

  version:當前數據節點數據內容的版本號

  cversion:當前數據節點子節點的版本號

  aversion:當前數據節點ACL變更版本號

Watcher

  事件監聽器(Watcher)是ZooKeeper非常重要的特性,我們可以在節點上注冊Watcher,並且在一些特性事件觸發時候,服務器將事件通知到客戶端上

ACL

  ZooKeeper使用ACL(Access Control Lists)權限控制機制保證數據安全,有5個權限:

  CREATE:創建子節點的權限

  READ:獲取節點數據和子節點列表的權限

  WRITE:更新節點數據的權限

  DELETE:刪除子節點的權限

  ADMIN:設置節點ACL的權限

 

二.ZooKeeper能做啥

  我們可以回頭看最上面的圖,Hbase,Hadoop,Kafka等已經被廣泛應用在越來越多的大型分布式系統中,用來解決諸如配置管理,分布式通知/協調、集群管理和Master選舉等一系列分布式問題

  ZooKeeper在阿里的實踐有Dubbo,消息中間件Metamorphosis,分布式數據庫同步系統Otter,實時計算引擎Jstorm等

  • 數據發布/訂閱(配置中心)
  • 負載均衡
  • 分布式協調/通知
  • 集群管理
  • Master選舉
  • 分布式鎖

 

三.ZAB協議是啥

  可以這么說,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:服務器ID

  SID是一個數據,標識一台ZooKeeper集群中的機器,SID不能重復,和myid值一樣。(集群的配置文件中,server.id=host:port:port,這里的id就是myid,我們還需要在dataDir參數的目錄創建myid文件,就是這里的id)

ZXID:事務ID

  ZXID是一個事務ID,標記唯一一次服務器狀態的變更,某一時刻,集群中的每台機器的ZXID不一定都一致,之前已經說過了。它是一個64位的數字,低32位可以看作遞增計數器,高32位代表Leader周期epoch的編號

Vote:投票

  我們可以看下Vote的數據結構:

  接下來我們來解釋一下每個字段的意思:

  id:被選舉的Leader的SID值

  zxid:被選舉的Leader的事務ID

  electionEpoch:邏輯時鍾

  peerEpoch:被選舉的Leader的epoch

  state:當前服務器的狀態

Quorum:過半機器數

  quorum=(n/2+1),假如集群總數是3,那么quorum就是2

 

ZAB協議三個階段

階段一:發現

  階段一就是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,然后所有服務器完成對事務的提交。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM