ZooKeeper的十二連問,你頂得了嘛?


前言

一線大廠ZooKeeper的十二連問,你頂得了嘛?

本文已經收錄到github

https://github.com/whx123/JavaHome

1. 面試官:工作中使用過Zookeeper嘛?你知道它是什么,有什么用途呢?

小菜雞的我:

  • 有使用過的,使用ZooKeeper作為 dubbo的注冊中心,使用ZooKeeper實現 分布式鎖
  • ZooKeeper,它是一個開放源碼的 分布式協調服務,它是一個集群的管理者,它將簡單易用的接口提供給用戶。
  • 可以基於Zookeeper 實現諸如數據發布/訂閱、負載均衡、命名服務、分布式協調/通知、集群管理、Master 選舉、分布式鎖和分布式隊列 等功能
  • Zookeeper的 用途:命名服務、配置管理、集群管理、分布式鎖、隊列管理

用途跟功能不是一個意思咩?給我一個眼神,讓我自己體會

2. 面試官:說下什么是命名服務,什么是配置管理,又什么是集群管理吧

小菜雞的我(幸好我刷過面試題),無所畏懼

  • 命名服務就是

命名服務是指通過指定的名字來獲取資源或者服務地址。Zookeeper可以創建一個全局唯一的路徑,這個路徑就可以作為一個名字。被命名的實體可以是集群中的機器,服務的地址,或者是遠程的對象等。一些分布式服務框架(RPC、RMI)中的服務地址列表,通過使用命名服務,客戶端應用能夠根據特定的名字來獲取資源的實體、服務地址和提供者信息等。

  • 配置管理:

實際項目開發中,我們經常使用.properties或者xml需要配置很多信息,如數據庫連接信息、fps地址端口等等。因為你的程序一般是分布式部署在不同的機器上(如果你是單機應用當我沒說),如果把程序的這些配置信息保存在zk的znode節點下,當你要修改配置,即znode會發生變化時,可以通過改變zk中某個目錄節點的內容,利用watcher通知給各個客戶端,從而更改配置。

  • 集群管理

集群管理包括集群監控和集群控制,其實就是監控集群機器狀態,剔除機器和加入機器。zookeeper可以方便集群機器的管理,它可以實時監控znode節點的變化,一旦發現有機器掛了,該機器就會與zk斷開連接,對用的臨時目錄節點會被刪除,其他所有機器都收到通知。新機器加入也是類似醬紫,所有機器收到通知:有新兄弟目錄加入啦。

3. 面試官:你提到了znode節點,那你知道znode有幾種類型呢?zookeeper的數據模型是怎樣的呢?

小菜雞的我(我先想想):

zookeeper的數據模型

ZooKeeper的視圖數據結構,很像Unix文件系統,也是樹狀的,這樣可以確定每個路徑都是唯一的。zookeeper的節點統一叫做znode,它是可以通過路徑來標識,結構圖如下:

znode的4種類型

根據節點的生命周期,znode可以分為4種類型,分別是持久節點(PERSISTENT)、持久順序節點(PERSISTENT_SEQUENTIAL)、臨時節點(EPHEMERAL)、臨時順序節點(EPHEMERAL_SEQUENTIAL)

  • 持久節點(PERSISTENT)

這類節點被創建后,就會一直存在於Zk服務器上。直到手動刪除。

  • 持久順序節點(PERSISTENT_SEQUENTIAL)

它的基本特性同持久節點,不同在於增加了順序性。父節點會維護一個自增整性數字,用於子節點的創建的先后順序。

  • 臨時節點(EPHEMERAL)

臨時節點的生命周期與客戶端的會話綁定,一旦客戶端會話失效(非TCP連接斷開),那么這個節點就會被自動清理掉。zk規定臨時節點只能作為葉子節點。

  • 臨時順序節點(EPHEMERAL_SEQUENTIAL)

基本特性同臨時節點,添加了順序的特性。

4、面試官:你知道znode節點里面存儲的是什么嗎?每個節點的數據最大不能超過多少呢?

小菜雞的我:

znode節點里面存儲的是什么?

Znode數據節點的代碼如下

public class DataNode implements Record {
    byte data[];                    
    Long acl;                       
    public StatPersisted stat;       
    private Set<String> children = null; 
}

哈哈,Znode包含了存儲數據、訪問權限、子節點引用、節點狀態信息,如圖:

  • data: znode存儲的業務數據信息
  • ACL: 記錄客戶端對znode節點的訪問權限,如IP等。
  • child: 當前節點的子節點引用
  • stat: 包含Znode節點的狀態信息,比如 事務id、版本號、時間戳等等。

每個節點的數據最大不能超過多少呢

為了保證高吞吐和低延遲,以及數據的一致性,znode只適合存儲非常小的數據,不能超過1M,最好都小於1K。

5、面試官:你知道znode節點上的監聽機制嘛?講下Zookeeper watch機制吧。

小菜雞的我:

  • Watcher機制
  • 監聽機制的工作原理
  • Watcher特性總結

Watcher監聽機制

Zookeeper 允許客戶端向服務端的某個Znode注冊一個Watcher監聽,當服務端的一些指定事件觸發了這個Watcher,服務端會向指定客戶端發送一個事件通知來實現分布式的通知功能,然后客戶端根據 Watcher通知狀態和事件類型做出業務上的改變。

可以把Watcher理解成客戶端注冊在某個Znode上的觸發器,當這個Znode節點發生變化時(增刪改查),就會觸發Znode對應的注冊事件,注冊的客戶端就會收到異步通知,然后做出業務的改變。

Watcher監聽機制的工作原理

  • ZooKeeper的Watcher機制主要包括客戶端線程、客戶端 WatcherManager、Zookeeper服務器三部分。
  • 客戶端向ZooKeeper服務器注冊Watcher的同時,會將Watcher對象存儲在客戶端的WatchManager中。
  • 當zookeeper服務器觸發watcher事件后,會向客戶端發送通知, 客戶端線程從 WatcherManager 中取出對應的 Watcher 對象來執行回調邏輯。

Watcher特性總結

  • 一次性: 一個Watch事件是一個一次性的觸發器。一次性觸發,客戶端只會收到一次這樣的信息。
  • 異步的: Zookeeper服務器發送watcher的通知事件到客戶端是異步的,不能期望能夠監控到節點每次的變化,Zookeeper只能保證最終的一致性,而無法保證強一致性。
  • 輕量級: Watcher 通知非常簡單,它只是通知發生了事件,而不會傳遞事件對象內容。
  • 客戶端串行: 執行客戶端 Watcher 回調的過程是一個串行同步的過程。
  • 注冊 watcher用getData、exists、getChildren方法
  • 觸發 watcher用create、delete、setData方法

6、面試官:你對Zookeeper的數據結構都有一定了解,那你講下Zookeeper的特性吧

小菜雞的我:(我背過書,啊哈哈) Zookeeper 保證了如下分布式一致性特性:

  • 順序一致性:從同一客戶端發起的事務請求,最終將會嚴格地按照順序被應用到 ZooKeeper 中去。
  • 原子性:所有事務請求的處理結果在整個集群中所有機器上的應用情況是一致的,也就是說,要么整個集群中所有的機器都成功應用了某一個事務,要么都沒有應用。
  • 單一視圖:無論客戶端連到哪一個 ZooKeeper 服務器上,其看到的服務端數據模型都是一致的。
  • 可靠性: 一旦服務端成功地應用了一個事務,並完成對客戶端的響應,那么該事務所引起的服務端狀態變更將會被一直保留下來。
  • 實時性(最終一致性): Zookeeper 僅僅能保證在一定的時間段內,客戶端最終一定能夠從服務端上讀取到最新的數據狀態。

7、面試官:你剛提到順序一致性,那zookeeper是如何保證事務的順序一致性的呢?

小菜雞的我:(完蛋了這題不會)

這道題可以看下這篇文章(本題答案來自該文章):聊一聊ZooKeeper的順序一致性[1] https://time.geekbang.org/column/article/239261

需要了解事務ID,即zxid。ZooKeeper的在選舉時通過比較各結點的zxid和機器ID選出新的主結點的。zxid由Leader節點生成,有新寫入事件時,Leader生成新zxid並隨提案一起廣播,每個結點本地都保存了當前最近一次事務的zxid,zxid是遞增的,所以誰的zxid越大,就表示誰的數據是最新的。

ZXID的生成規則如下:

ZXID有兩部分組成:

  • 任期:完成本次選舉后,直到下次選舉前,由同一Leader負責協調寫入;
  • 事務計數器:單調遞增,每生效一次寫入,計數器加一。

ZXID的低32位是計數器,所以同一任期內,ZXID是連續的,每個結點又都保存着自身最新生效的ZXID,通過對比新提案的ZXID與自身最新ZXID是否相差“1”,來保證事務嚴格按照順序生效的。

8、面試官:你提到了Leader,你知道Zookeeper的服務器有幾種角色嘛?Zookeeper下Server工作狀態又有幾種呢?

小菜雞的我:

Zookeeper 服務器角色

Zookeeper集群中,有Leader、Follower和Observer三種角色

Leader

Leader服務器是整個ZooKeeper集群工作機制中的核心,其主要工作:

  • 事務請求的唯一調度和處理者,保證集群事務處理的順序性
  • 集群內部各服務的調度者

Follower

Follower服務器是ZooKeeper集群狀態的跟隨者,其主要工作:

  • 處理客戶端非事務請求,轉發事務請求給Leader服務器
  • 參與事務請求Proposal的投票
  • 參與Leader選舉投票

Observer

Observer是3.3.0 版本開始引入的一個服務器角色,它充當一個觀察者角色——觀察ZooKeeper集群的最新狀態變化並將這些狀態變更同步過來。其工作:

  • 處理客戶端的非事務請求,轉發事務請求給 Leader 服務器
  • 不參與任何形式的投票

Zookeeper下Server工作狀態

服務器具有四種狀態,分別是 LOOKING、FOLLOWING、LEADING、OBSERVING。

  • 1.LOOKING:尋找Leader狀態。當服務器處於該狀態時,它會認為當前集群中沒有 Leader,因此需要進入 Leader 選舉狀態。
  • 2.FOLLOWING:跟隨者狀態。表明當前服務器角色是Follower。
  • 3.LEADING:領導者狀態。表明當前服務器角色是Leader。
  • 4.OBSERVING:觀察者狀態。表明當前服務器角色是Observer。

9、面試官:你說到服務器角色是基於ZooKeeper集群的,那你畫一下ZooKeeper集群部署圖吧?ZooKeeper是如何保證主從節點數據一致性的呢?

小菜雞的我:

ZooKeeper集群部署圖

ZooKeeper集群是一主多從的結構:

  • 如果是寫入數據,先寫入主服務器(主節點),再通知從服務器。
  • 如果是讀取數據,既讀主服務器的,也可以讀從服務器的。

ZooKeeper如何保證主從節點數據一致性

我們知道集群是主從部署結構,要保證主從節點一致性問題,無非就是兩個主要問題:

  • 主服務器掛了,或者重啟了
  • 主從服務器之間同步數據~

Zookeeper是采用ZAB協議(Zookeeper Atomic Broadcast,Zookeeper原子廣播協議)來保證主從節點數據一致性的,ZAB協議支持崩潰恢復和消息廣播兩種模式,很好解決了這兩個問題:

  • 崩潰恢復:Leader掛了,進入該模式,選一個新的leader出來
  • 消息廣播: 把更新的數據,從Leader同步到所有Follower

Leader服務器掛了,所有集群中的服務器進入LOOKING狀態,首先,它們會選舉產生新的Leader服務器;接着,新的Leader服務器與集群中Follower服務進行數據同步,當集群中超過半數機器與該 Leader服務器完成數據同步之后,退出恢復模式進入消息廣播模式。Leader 服務器開始接收客戶端的事務請求生成事務Proposal進行事務請求處理。

10、面試官:Leader掛了,進入崩潰恢復,是如何選舉Leader的呢?你講一下ZooKeeper選舉機制吧

小菜雞的我:

服務器啟動或者服務器運行期間(Leader掛了),都會進入Leader選舉,我們來看一下~假設現在ZooKeeper集群有五台服務器,它們myid分別是服務器1、2、3、4、5,如圖:

服務器啟動的Leader選舉

zookeeper集群初始化階段,服務器(myid=1-5)依次啟動,開始zookeeper選舉Leader~

  • 服務器1(myid=1)啟動,當前只有一台服務器,無法完成Leader選舉
  • 服務器2(myid=2)啟動,此時兩台服務器能夠相互通訊,開始進入Leader選舉階段
  1. 每個服務器發出一個投票

服務器1 和 服務器2都將自己作為Leader服務器進行投票,投票的基本元素包括:服務器的myid和ZXID,我們以(myid,ZXID)形式表示。初始階段,服務器1和服務器2都會投給自己,即服務器1的投票為(1,0),服務器2的投票為(2,0),然后各自將這個投票發給集群中的其他所有機器。

  1. 接受來自各個服務器的投票

每個服務器都會接受來自其他服務器的投票。同時,服務器會校驗投票的有效性,是否本輪投票、是否來自LOOKING狀態的服務器。

  1. 處理投票

收到其他服務器的投票,會將被人的投票跟自己的投票PK,PK規則如下:

  • 優先檢查ZXID。ZXID比較大的服務器優先作為leader。
  • 如果ZXID相同的話,就比較myid,myid比較大的服務器作為leader。 服務器1的投票是(1,0),它收到投票是(2,0),兩者zxid都是0,因為收到的myid=2,大於自己的myid=1,所以它更新自己的投票為(2,0),然后重新將投票發出去。對於服務器2呢,即不再需要更新自己的投票,把上一次的投票信息發出即可。
  1. 統計投票

每次投票后,服務器會統計所有投票,判斷是否有過半的機器接受到相同的投票信息。服務器2收到兩票,少於3(n/2+1,n為總服務器),所以繼續保持LOOKING狀態

  • 服務器3(myid=3)啟動,繼續進入Leader選舉階段

跟前面流程一致,服務器1和2先投自己一票,因為服務器3的myid最大,所以大家把票改投給它。此時,服務器為3票(大於等於n/2+1),所以服務器3當選為Leader。 服務器1,2更改狀態為FOLLOWING,服務器3更改狀態為LEADING;

  • 服務器4啟動,發起一次選舉。

此時服務器1,2,3已經不是LOOKING狀態,不會更改選票信息。選票信息結果:服務器3為3票,服務器4為1票。服務器4並更改狀態為FOLLOWING;

  • 服務器5啟動,發起一次選舉。

同理,服務器也是把票投給服務器3,服務器5並更改狀態為FOLLOWING;

  • 投票結束,服務器3當選為Leader

服務器運行期間的Leader選舉

zookeeper集群的五台服務器(myid=1-5)正在運行中,突然某個瞬間,Leader服務器3掛了,這時候便開始Leader選舉~

  • 1.變更狀態

Leader 服務器掛了之后,余下的非Observer服務器都會把自己的服務器狀態更改為LOOKING,然后開始進入Leader選舉流程。

  • 2.每個服務器發起投票

每個服務器都把票投給自己,因為是運行期間,所以每台服務器的ZXID可能不相同。假設服務1,2,4,5的zxid分別為333,666,999,888,則分別產生投票(1,333),(2,666),(4,999)和(5,888),然后各自將這個投票發給集群中的其他所有機器。

  • 3.接受來自各個服務器的投票
  • 4.處理投票

投票規則是跟Zookeeper集群啟動期間一致的,優先檢查ZXID,大的優先作為Leader,所以顯然服務器zxid=999具有優先權。

  • 5.統計投票
  • 6.改變服務器狀態

11、面試官: 你前面提到在項目中使用過Zookeeper的分布式鎖,講一下zk分布式鎖的實現原理吧?

小菜雞的我: Zookeeper就是使用臨時順序節點特性實現分布式鎖的。

  • 獲取鎖過程 (創建臨時節點,檢查序號最小)
  • 釋放鎖 (刪除臨時節點,監聽通知)

獲取鎖過程

  • 當第一個客戶端請求過來時,Zookeeper客戶端會創建一個持久節點/locks。如果它(Client1)想獲得鎖,需要在locks節點下創建一個順序節點lock1.如圖
  • 接着,客戶端Client1會查找locks下面的所有臨時順序子節點,判斷自己的節點lock1是不是排序最小的那一個,如果是,則成功獲得鎖。
  • 這時候如果又來一個客戶端client2前來嘗試獲得鎖,它會在locks下再創建一個臨時節點lock2
  • 客戶端client2一樣也會查找locks下面的所有臨時順序子節點,判斷自己的節點lock2是不是最小的,此時,發現lock1才是最小的,於是獲取鎖失敗。獲取鎖失敗,它是不會甘心的,client2向它排序靠前的節點lock1注冊Watcher事件,用來監聽lock1是否存在,也就是說client2搶鎖失敗進入等待狀態。
  • 此時,如果再來一個客戶端Client3來嘗試獲取鎖,它會在locks下再創建一個臨時節點lock3
  • 同樣的,client3一樣也會查找locks下面的所有臨時順序子節點,判斷自己的節點lock3是不是最小的,發現自己不是最小的,就獲取鎖失敗。它也是不會甘心的,它會向在它前面的節點lock2注冊Watcher事件,以監聽lock2節點是否存在。

釋放鎖

我們再來看看釋放鎖的流程,zookeeper的客戶端業務完成或者故障,都會刪除臨時節點,釋放鎖。如果是任務完成,Client1會顯式調用刪除lock1的指令 如果是客戶端故障了,根據臨時節點得特性,lock1是會自動刪除的 lock1節點被刪除后,Client2可開心了,因為它一直監聽着lock1。lock1節點刪除,Client2立刻收到通知,也會查找locks下面的所有臨時順序子節點,發下lock2是最小,就獲得鎖。

同理,Client2獲得鎖之后,Client3也對它虎視眈眈,啊哈哈~

12. 面試官:好的,最后一道題,你說說dubbo和Zookeeper的關系吧,為什么選擇Zookeeper作為注冊中心?

小菜雞的我(答了這么多道題,不會還不給我過吧?):

dubbo的注冊中心可以選Zookeeper,memcached,redis等。為什么選擇Zookeeper,因為它的功能特性咯~

  • 命名服務,服務提供者向Zookeeper指定節點寫入url,完成服務發布。
  • 負載均衡,注冊中心的承載能力有限,而Zookeeper集群配合web應用很容易達到負載均衡。
  • zk支持監聽事件,特別適合發布/訂閱的場景,dubbo的生產者和消費者就類似這場景。
  • 數據模型簡單,數據存在內存,可謂高性能
  • Zookeeper其他特點都可以搬出來講一下~

個人公眾號

參考與感謝

  • <<從Paxos到Zookeeper 分布式一致性原理與實踐>>
  • zookeeper面試題 [2]
  • 28道進階必備ZooKeeper面試真題(建議收藏!) [3]
  • 漫畫:什么是ZooKeeper? [4]
  • 聊一聊ZooKeeper的順序一致性 [5]
  • Zookeeper——一致性協議:Zab協議 [6]
  • Zookeeper的選舉機制原理(圖文深度講解) [7]
  • 漫畫:如何用Zookeeper實現分布式鎖?

Reference

[1]

聊一聊ZooKeeper的順序一致性: https://time.geekbang.org/column/article/239261

[2]

zookeeper面試題: https://segmentfault.com/a/1190000014479433

[3]

28道進階必備ZooKeeper面試真題(建議收藏!): https://zhuanlan.zhihu.com/p/102168788

[4]

漫畫:什么是ZooKeeper?: https://juejin.im/post/6844903608685707271

[5]

聊一聊ZooKeeper的順序一致性: https://time.geekbang.org/column/article/239261

[6]

Zookeeper——一致性協議:Zab協議: https://www.jianshu.com/p/2bceacd60b8a

[7]

Zookeeper的選舉機制原理(圖文深度講解): https://blog.csdn.net/wx1528159409/article/details/84622762


免責聲明!

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



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