天天看點

一文看懂 ZooKeeper ,面試再也不用背八股

ZooKeeper知識點總結

  • 一、ZooKeeper 的工作機制
  • 二、ZooKeeper 中的 ZAB 協定
  • 三、資料模型與監聽器
  • 四、ZooKeeper 的選舉機制和流程

本文将以如下内容為主線講解ZooKeeper中的學習重點,包括 ZooKeeper 中的角色、ZAB協定、資料模型、選舉機制、監聽器原理以及應用場景等。會對相關的面試題或開發中常見内容,進行重點講解。

一文看懂 ZooKeeper ,面試再也不用背八股

接下來将帶領大家入門學習 ZooKeeper 系列的内容,力求通俗易懂,圖文并茂。

一、ZooKeeper 的工作機制

1. 什麼是ZooKeeper

ZooKeeper 是一個分布式協調服務,其設計的初衷是為分布式軟體提供一緻性服務。其本質上,就是檔案系統+通知機制。

ZooKeeper 提供了一個類似 Linux 檔案系統的樹形結構,ZooKeeper 的每個節點既可以是目錄也可以是資料,并且 ZooKeeper 還提供了對每個節點的監控與通知機制。

2. ZooKeeper 的工作機制

ZooKeeper 采用的是主從模式,有主節點和從節點。從設計模式的角度,它是一個基于觀察者模式設計的分布式服務管理架構,負責存儲和管理大家都關心的資料,然後接受觀察者的注冊,一旦這些資料的狀态發生變化,ZooKeeper 就将負責通知已經注冊的那些觀察者做出相應的反應。

3. ZooKeeper 的角色及其關系

ZooKeeper 中的角色包括 Leader、Follower、Observer。Leader 是叢集主節點,主要負責管理叢集狀态和接收使用者的寫請求;Follower 是從節點,主要負責叢集選舉投票和接收使用者的讀請求;Observer 的功能與 Follower 類似,隻是沒有投票權,主要用于分擔 Follower 的讀請求,降低叢集的負載。

一文看懂 ZooKeeper ,面試再也不用背八股

a. Leader

一個運作中的 Zookeeper 叢集隻有一個 Leader 服務,Leader 服務主要包括以下兩個指責:

  • 負責叢集資料的寫操作。所有寫操作必須要 Leader 完成之後,才可以将寫操作廣播到其他 Follower,并且隻有超過半數節點(不包括 Observer)寫入成功後,這些寫請求才算寫成功;
  • 發起并維護各個 Follower 以及 Observer 之間的心跳,以監控叢集的運作狀态。

b. Follower

一個 Zookeeper 叢集可以有多個 Follower,Follower通過心跳與 Leader 保持連接配接。Follower 服務主要有以下兩個指責:

  • 負責叢集資料的讀操作。Follower 在接受到一個用戶端請求之後,會先判斷該請求是讀請求還是寫請求,若為讀請求,則 Follower 從本地節點上讀取資料并傳回給用戶端;若為寫請求,則 Follower 會将寫請求轉發給 Leader 來處理。
  • 參與叢集中 Leader 的選舉。當 Leader 失效之後,Follower 需要在叢集選舉時進行投票;(後續會詳細講解選舉機制)

c. Observer

一個 Zookeeper 叢集可以有多個 Observer,Observer 的主要職責是負責叢集資料的讀操作,其功能同以上介紹的 Follower 的功能類似,主要的差别就是 Observer 沒有投票權。

4. 面試題:Follower 已經具備了 Observer 的所有功能,為什麼還要設計 Observer 角色 ?

這是因為 ZooKeeper 叢集在運作過程中要支援更多的用戶端并發的操作,就需要增加更多的服務執行個體,而過多的服務執行個體會使得叢集的投票階段變得複雜,選舉時間過長不利于叢集故障的快速恢複。

是以,ZooKeeper 引入了 Observer 角色,Observer 不參與投票,隻負責接收用戶端來的讀請求,以及将寫請求轉發給 Leader 。加入更多的 Observer 節點,不僅提高了 ZooKeeper 叢集的吞吐量,保障了系統的穩定性。

二、ZooKeeper 中的 ZAB 協定

前面介紹了 ZooKeeper 的基本概念、角色、工作機制等内容,為了後續更好地學習 ZooKeeper 的原理,本節先給大家介紹一種分布式一緻性協定——ZAB(ZooKeeper Atomic Broadcast,ZooKeeper 原子消息廣播協定)。

1. 什麼是ZAB

在介紹 ZAB 之前,先給大家介紹下 ZooKeeper 的由來。

ZooKeeper 最早起源于雅虎研究院的一個研究小組,當時雅虎内部很多大型系統都需要依賴一個類似的系統來進行分布式協調,為了讓把精力集中在業務邏輯上,雅虎研發人員開發了一個通用的解決了單點問題的分布式協調架構。

ZooKeeper 名字的由來:

立項之初,考慮到很多項目都是使用動物的名字來命名的,雅虎的工程師希望給這個項目也取一個動物的名字。有人開玩笑地說:“在這樣下去,我們這兒就變成動物園了!”此話一出,大家紛紛表示就叫動物園管理者吧。

而 ZAB 協定最初也隻是為雅虎内部那些高吞吐量、低延遲的分布式系統場景設計的,它并不是一種通用的分布式一緻性算法,而是專門為 ZooKeeper 設計的一種支援崩潰恢複的原子廣播協定,實作了一種主備模式的系統架構來保持叢集中各副本之間資料的一緻性。

2. 兩個概念

1)目前叢集的周期号:Epoch

叢集中每次 Leader 的重新選舉都會産生一個新的周期号(也有叫年代号的,都一個意思),周期号的産生規則則是在上一個周期号上加1,這樣當之前的 Leader 奔潰恢複後會發現自己的周期号比目前的周期号小,說明此時叢集已經産生了一個新的 Leader,舊的 Leader 會再次以 Follower 的角色加入叢集。

2)ZAB 協定的事務編号:Zxid

Zxid 是一個64位的數字,其中低32位存儲的是一個簡單的單調遞增的計數器,針對用戶端的每個事務請求,計數器都會加1。高32位存儲的是 Leader 的周期号 Epoch。每次選舉産生一個新的 Leader 時,該 Leader 就會從目前伺服器的日志中取最大事務的 Zxid,擷取其中高32位的 Epoch 值并加1,以此作為一個新的 Epoch,并會将低32位從0開始重新計數。

3. 兩種模式

1)叢集選主:恢複模式

當叢集 Leader 出現崩潰,或者由于網絡原因導緻 Leader 和過半的 Follower 失去聯系,那麼叢集将開始選主,該過程為恢複模式。

Leader 的選舉機制不僅可以讓 Leader 節點知道自身被選舉為 Leader,同時還能需要讓叢集中其他節點也能快速感覺到選舉的新的 Leader 節點。

2)資料同步:廣播模式

當 Leader 被選舉出來後,Leader 将最新的叢集狀态廣播給其他 Follower,該過程為廣播模式。在半數以上的 Follower 完成與 Leader 的狀态同步後,廣播模式結束。

4. ZAB 的實作過程

1)選舉階段

選舉階段的目的就是産生一個準 Leader,節點在一開始都處于選舉階段,隻要有一個節點得到超過半數節點的票數,那麼它就可以當選準Leader,隻有到達第三階段(同步階段)這個準Leader才會成為真正的Leader。

一文看懂 ZooKeeper ,面試再也不用背八股

2)發現階段

在該階段中 Follower 和上一階段選舉出的準 Leader 進行通信,同步 Follower 最近接收的事務提議。這一階段的目的是發現目前大多數節點接收的最新提議,并且準 Leader 生成新 的epoch,然後讓 Follower 接收,更新它們的acceptedEpoch。

一文看懂 ZooKeeper ,面試再也不用背八股

如果節點1認為節點L是 Leader,那麼當節點1嘗試連接配接節點L時,如果連接配接遭到拒絕,則叢集将會重新進入選舉階段。

3)同步階段

同步階段主要是将 Leader 在前一階段獲得的最新提議資訊同步到叢集中所有的副本。并且隻有當超過半數的節點都同步完成後,準 Leader 才會成為真正的 Leader 。Follower 隻會接收 Zxid比自己 lastZxid 大的提議。

一文看懂 ZooKeeper ,面試再也不用背八股

同步完成之後,叢集的選主操作才算完成,新的 Leader 将産生。

4)廣播階段

在該階段,ZooKeeper 叢集正式對外提供事務服務,這時 Leader 進行消息廣播,将其上的狀态通知到其他 Follower。若後續有新的節點加入進來,則 Leader 會對新節點進行狀态同步。

三、資料模型與監聽器

ZooKeeper 可用于統一命名服務、配置管理、叢集管理、分布式通知協調、分布式鎖等場景,在這些應用場景中, ZooKeeper 内部是如何做到分布式資料一緻性的呢?本節将給大家介紹下 ZooKeeper 内部是如何做到分布式資料一緻性的。

ZooKeeper 使用了一個樹形結構的命名空間來表示其資料結構,其視圖結構和标準的 Unix 檔案系統非常類似,但沒有引入傳統檔案系統中目錄和檔案等相關概念,而是将 ZooKeeper 樹中的每一個節點都稱之為一個 Znode。其資料結構如下圖所示。

一文看懂 ZooKeeper ,面試再也不用背八股

類似檔案系統的目錄樹,ZooKeeper 樹中的每個節點都可以擁有子節點,而不同的是,每個 Znode 節點都存儲了資料資訊,同時也提供了對節點資訊的監控等操作。

1. Znode 的資料模型

Znode 是 ZooKeeper 中資料的最小單元,每個 Znode 都兼具檔案和目錄兩種特點,既能像檔案一樣儲存和維護資料,又可以由一系列使用斜杠(/)進行分割的方式作為路徑辨別的一部分。每個 Znode 都有以下三部分組成。

  • Stat:狀态資訊,用于存儲該 Znode 的版本、權限、時間戳等資訊;
  • Data:實際存儲的資料;
  • Children:對子節點的資訊描述;

需要特别說明的是,Znode 節點雖然可以存儲資料資訊,但它并不能像資料庫那樣存儲大量的資料,Znode 的設計初衷就是存儲分布式應用中的配置檔案、叢集狀态等中繼資料資訊。

2. Znode 的控制通路

1)ACL

ACL(Access Control List) 為通路控制清單,應用程式會根據實際需求将使用者分為隻讀、隻寫以及讀寫使用者,每一個 Znode 節點都會有一個 ACL 用來限制不同的使用者對節點的通路權限。

2)原子操作

每一個 Znode 節點上都具有原子操作的特性,讀操作将擷取與節點相關的資料,寫操作将替換節點上的資料,上期文章中講到 ZooKeeper 都會為每一個事務請求配置設定一個全局唯一的事務編号 Zxid,每一個 Zxid 就對應一次更新操作,并可以通過 Zxid 來識别出更新操作請求的全局順序。

3. Znode 的節點類型

ZooKeeper 中的節點有兩種,分别為臨時節點和永久節點。節點的類型在建立時即被确定,并且不能改變。

1)臨時節點

臨時節點常被應用于心跳監控,舉個栗子,設定過期時間為 30s,要求各個子節點對應的服務端每 5s 發送一次心跳到 ZooKeeper 叢集,當服務端連續 30s 沒有向 ZooKeeper 彙報心跳資訊,也就是連續6次沒有收到心跳資訊,就認為該節點當機了,并将其從服務清單中移除。

臨時節點的生命周期依賴于建立它們的會話(Session)。一旦會話結束,臨時節點将被自動删除,當然可以也可以手動删除。

另外,ZooKeeper 的臨時節點不允許擁有子節點。

2)永久節點

永久節點的資料會一直存儲着,直到使用者調用接口将其資料删除,該節點一般用于存儲一些永久性的配置資訊。

4. Znode 的監聽器機制( 面試重點)

ZooKeeper 的每個節點上都有一個 Watcher 用于監控節點資料的變化,當節點狀态發生改變時(Znode 新增、删除、修改)将會觸發 Wahcher 所對應的操作。在 Watcher 被觸發時,ZooKeeper 會向監控該節點的用戶端發送一條通知說明節點的變化情況。

一文看懂 ZooKeeper ,面試再也不用背八股

具體實作流程就是,用戶端向 ZooKeeper 伺服器注冊 Watcher 的同時,會将 Watcher 對象存儲在用戶端的 WatchManager 中。當 ZooKeeper 伺服器端觸發 Watcher 事件後,會向用戶端發送通知,用戶端線程從 WatchManager 中取出對應的 Watcher 對象來執行回調邏輯。

四、ZooKeeper 的選舉機制和流程

我們在本系列的第一期就介紹了 ZooKeeper 叢集中的三個伺服器角色:Leader、Follower 和 Observer。其中,Leader 選舉是 ZooKeeper 中最重要的技術之一,也是保證分布式資料一緻性的關鍵所在。本期内容将重點講解 Leader 是如何被選舉的。

1. 選舉機制概述

Zookeeper 在配置檔案中并沒有指定 Master 和 Slave。但是,Zookeeper 工作時, 是有一個節點為 Leader,其他則為 Follower,而這個 Leader 是通過内部的選舉機制臨時産生的。

每個 Server 首先都提議自己是 Leader,并為自己投票,然後将投票結果與其他 Server 的選票進行對比,權重大的勝出,使用權重較大的選票更新自身的投票箱,我們介紹下伺服器啟動時期的 Leader 選舉。

1)每一個 Server 都會發出一個投票

在叢集初次啟動時,每個 Server 都會推薦自己為 Leader,然後各自将這個投票發給叢集中其他 Server。

2)接收來自各個 Server 的投票

每個 Server 在接收到其他 Server 的投票後,首先會判斷該票的有效性,包括檢查是否本輪投票,是否來自 Looking 狀态的 Server。(Looking 狀态表示目前叢集正處于選舉狀态)

3)處理投票

針對每一個投票,Server 都會将别人的投票和自己的投票進行 PK,計算出 Zxid 最大的 Server,并将該 Server 設定成下一次投票推薦的 Server。

4)統計投票

每次投票結束之後,都會統計所有投票,擷取投票最多的 Server 将成為獲勝者,如果獲勝者的票數超過叢集個數的一半,則該 Server 将為推選為 Leader。否則繼續投票,直至 Leader 被選舉出來。

5)改變伺服器狀态

一旦 Leader 确定後,Leader 會通知其他 Follower 叢集已經成為 Uptodate 狀态,Follower 在收到 Uptodate 消息後,接收 Client 的請求并開始對外提供服務。

2. 選舉 Leader 的具體執行個體

上述的選舉過程比較抽象,我們以一個有5個節點的叢集為例,目前均為 shutdown 狀态。

一文看懂 ZooKeeper ,面試再也不用背八股

按照 Server 的編号依次啟動,看下整個的選舉過程是如何實作的。

1)Server 1 啟動

一文看懂 ZooKeeper ,面試再也不用背八股

Server 1 啟動後會提議自己為 Leader 并為自己投票,然後将投票結果發送給其他 Server,由于其他 Server 還未啟動,是以收不到任何回報資訊,此時 Server 1 會處于 Looking 狀态。

2)Server 2 啟動

一文看懂 ZooKeeper ,面試再也不用背八股

Server 2 啟動後會提議自己為 Leader 并為自己投票,然後與 Server 1 交換投票結果,由于 Server 2 的編号大于 Server 1,是以 Server 2 勝出。但是,由于投票數未過叢集數的一半,兩個 Server 仍然均處于 Looking 狀态。

3)Server 3 啟動

一文看懂 ZooKeeper ,面試再也不用背八股

Server 3 啟動後會提議自己為 Leader 并為自己投票,然後與 Server 2、Server 3 交換投票結果,由于 Server 3 的編号最大,是以 Server 3 勝出。此時, Server 3 的票數大于叢集數的一半了,是以 Server 3 會更新為 Leader ,Server 1、Server 2 更新為 Follower。

4)Server 4 啟動

一文看懂 ZooKeeper ,面試再也不用背八股

Server 4 啟動後會提議自己為 Leader 并為自己投票,然後與 Server 1、Server 2、Server 3 交換投票結果,發現 Server 3 已經成為了 Leader,是以 Server 4 也成為了 Follower。

5)Server 5 啟動

一文看懂 ZooKeeper ,面試再也不用背八股

與 Server 4 一樣,Server 5 啟動後會給自己投票,然後與其他 Server 交換資訊,發現 Server 3 已經成為了 Leader,是以 Server 5 也成為了 Follower。

投票 vote 的資料結構
  • id:伺服器ID,用來唯一辨別 ZooKeeper 叢集中的伺服器;
  • Zxid:事務ID,用來唯一辨別一次伺服器狀态的變更;
  • electionEpoch:代表目前伺服器的選舉輪次,是一個自增序列;
  • peerEpoch:被推舉的 Leader 的選舉輪次;
  • state:目前伺服器的狀态。