1. 程式人生 > >搞懂ZooKeeper到底是做啥的

搞懂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,然後所有伺服器完成對事務的提交。

&n