ZooKeeper面試專題及答案

1.ZooKeeper 是什麼?
ZooKeeper 是一個分佈式的,開放源碼的分佈式應用程序協調服務,是 Google 的 Chubby 一個開源的實現,
它是集羣的管理者,監視着集羣中各個節點的狀態根據節點提交的反饋進行下一步合理操作。最終,將簡單易
用的接口和性能高效、功能穩定的系統提供給用戶。
客戶端的讀請求可以被集羣中的任意一臺機器處理,如果讀請求在節點上註冊了監聽器,這個監聽器也是由所
連接的 zookeeper 機器來處理。對於寫請求,這些請求會同時發給其他 zookeeper 機器並且達成一致後,請
求才會返回成功。因此,隨着 zookeeper 的集羣機器增多,讀請求的吞吐會提高但是寫請求的吞吐會下降。
有序性是 zookeeper 中非常重要的一個特性,所有的更新都是全局有序的,每個更新都有一個唯一的時間戳,
這個時間戳稱爲 zxid(Zookeeper Transaction Id)。而讀請求只會相對於更新有序,也就是讀請求的返回
結果中會帶有這個 zookeeper 最新的 zxid。
2.ZooKeeper 提供了什麼?

1、文件系統

2、通知機制
3.Zookeeper 文件系統
Zookeeper 提供一個多層級的節點命名空間(節點稱爲 znode)。與文件系統不同的是,這些節點都可以設置
關聯的數據,而文件系統中只有文件節點可以存放數據而目錄節點不行。Zookeeper 爲了保證高吞吐和低延
遲,在內存中維護了這個樹狀的目錄結構,這種特性使得 Zookeeper 不能用於存放大量的數據,每個節點的存
放數據上限爲 1M。

4.四種類型的 znode
1、PERSISTENT-持久化目錄節點
客戶端與 zookeeper 斷開連接後,該節點依舊存在
2、PERSISTENT_SEQUENTIAL-持久化順序編號目錄節點
客戶端與 zookeeper 斷開連接後,該節點依舊存在,只是 Zookeeper 給該節點名稱進行順序編號
3、EPHEMERAL-臨時目錄節點
客戶端與 zookeeper 斷開連接後,該節點被刪除
4、EPHEMERAL_SEQUENTIAL-臨時順序編號目錄節點
客戶端與 zookeeper 斷開連接後,該節點被刪除,只是 Zookeeper 給該節點名稱進行順序編號
5.Zookeeper 通知機制
client 端會對某個 znode 建立一個 watcher 事件,當該 znode 發生變化時,這些 client 會收到 zk 的通知,
然後 client 可以根據 znode 變化來做出業務上的改變等。

6.Zookeeper 做了什麼?
1、命名服務
2、配置管理
3、集羣管理
4、分佈式鎖
5、隊列管理

87.zk 的命名服務(文件系統)
命名服務是指通過指定的名字來獲取資源或者服務的地址,利用 zk 創建一個全局的路徑,即是唯一的路徑,這
個路徑就可以作爲一個名字,指向集羣中的集羣,提供的服務的地址,或者一個遠程的對象等等。

8.zk 的配置管理(文件系統、通知機制)
程序分佈式的部署在不同的機器上,將程序的配置信息放在 zk 的 znode 下,當有配置發生改變時,也就是
znode 發生變化時,可以通過改變 zk 中某個目錄節點的內容,利用 watcher 通知給各個客戶端,從而更改配
置。

9.Zookeeper 集羣管理(文件系統、通知機
制)
所謂集羣管理無在乎兩點:是否有機器退出和加入、選舉 master。
對於第一點,所有機器約定在父目錄下創建臨時目錄節點,然後監聽父目錄節點的子節點變化消息。一旦有機
器掛掉,該機器與 zookeeper 的連接斷開,其所創建的臨時目錄節點被刪除,所有其他機器都收到通知:某個
兄弟目錄被刪除,於是,所有人都知道:它上船了。
新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount 又有了,對於第二點,我們稍微改變
一下,所有機器創建臨時順序編號目錄節點,每次選取編號最小的機器作爲 master 就好。

10.Zookeeper 分佈式鎖(文件系統、通知
機制)
有了 zookeeper 的一致性文件系統,鎖的問題變得容易。鎖服務可以分爲兩類,一個是保持獨佔,另一個是控
制時序。
對於第一類,我們將 zookeeper 上的一個 znode 看作是一把鎖,通過 createznode 的方式來實現。所有客戶
端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。用完刪除掉自己創建的
distribute_lock 節點就釋放出鎖。
對於第二類, /distribute_lock 已經預先存在,所有客戶端在它下面創建臨時順序編號目錄節點,和選
master 一樣,編號最小的獲得鎖,用完刪除,依次方便。

11.獲取分佈式鎖的流程
在獲取分佈式鎖的時候在 locker 節點下創建臨時順序節點,釋放鎖的時候刪除該臨時節點。客戶端調用
createNode 方法在 locker 下創建臨時順序節點,
然後調用 getChildren(“locker”)來獲取 locker 下面的所有子節點,注意此時不用設置任何 Watcher。客戶
端獲取到所有的子節點 path 之後,如果發現自己創建的節點在所有創建的子節點序號最小,那麼就認爲該客戶
端獲取到了鎖。如果發現自己創建的節點並非 locker 所有子節點中最小的,說明自己還沒有獲取到鎖,此時客
戶端需要找到比自己小的那個節點,然後對其調用 exist()方法,同時對其註冊事件監聽器。之後,讓這個被關
注的節點刪除,則客戶端的 Watcher 會收到相應通知,此時再次判斷自己創建的節點是否是 locker 子節點中
序號最小的,如果是則獲取到了鎖,如果不是則重複以上步驟繼續獲取到比自己小的一個節點並註冊監聽。當
前這個過程中還需要許多的邏輯判斷。
代碼的實現主要是基於互斥鎖,獲取分佈式鎖的重點邏輯在於 BaseDistributedLock,實現了基於
Zookeeper 實現分佈式鎖的細節。
12.Zookeeper 隊列管理(文件系統、通知機制)

兩種類型的隊列:
1、同步隊列,當一個隊列的成員都聚齊時,這個隊列纔可用,否則一直等待所有成員到達。
2、隊列按照 FIFO 方式進行入隊和出隊操作。
第一類,在約定目錄下創建臨時目錄節點,監聽節點數目是否是我們要求的數目。
第二類,和分佈式鎖服務中的控制時序場景基本原理一致,入列有編號,出列按編號。在特定的目錄下創建
PERSISTENT_SEQUENTIAL 節點,創建成功時 Watcher 通知等待的隊列,隊列刪除序列號最小的節點用以
消費。此場景下 Zookeeper 的 znode 用於消息存儲,znode 存儲的數據就是消息隊列中的消息內容,
SEQUENTIAL 序列號就是消息的編號,按序取出即可。由於創建的節點是持久化的,所以不必擔心隊列消息的
丟失問題。

13.Zookeeper 數據複製
Zookeeper 作爲一個集羣提供一致的數據服務,自然,它要在所有機器間做數據複製。數據複製的好處:
1、容錯:一個節點出錯,不致於讓整個系統停止工作,別的節點可以接管它的工作;
2、提高系統的擴展能力 :把負載分佈到多個節點上,或者增加節點來提高系統的負載能力;
3、提高性能:讓客戶端本地訪問就近的節點,提高用戶訪問速度。
從客戶端讀寫訪問的透明度來看,數據複製集羣系統分下面兩種:

1、寫主(WriteMaster) :對數據的修改提交給指定的節點。讀無此限制,可以讀取任何一個節點。這種情況下
客戶端需要對讀與寫進行區別,俗稱讀寫分離; 2、寫任意(Write Any):對數據的修改可提交給任意的節點,跟讀一樣。這種情況下,客戶端對集羣節點的角
色與變化透明。

對 zookeeper 來說,它採用的方式是寫任意。通過增加機器,它的讀吞吐能力和響應能力擴展性非常好,而
寫,隨着機器的增多吞吐能力肯定下降(這也是它建立 observer 的原因),而響應能力則取決於具體實現方
式,是延遲複製保持最終一致性,還是立即複製快速響應。

14.Zookeeper 工作原理
Zookeeper 的核心是原子廣播,這個機制保證了各個 Server 之間的同步。實現這個機制的協議叫做 Zab 協 議。Zab 協議有兩種模式,它們分別是恢復模式(選主)和廣播模式(同步)。當服務啓動或者在領導者崩潰
後,Zab 就進入了恢復模式,當領導者被選舉出來,且大多數 Server 完成了和 leader 的狀態同步以後,恢復
模式就結束了。狀態同步保證了 leader 和 Server 具有相同的系統狀態。

15.zookeeper 是如何保證事務的順序一致性
的?
zookeeper 採用了遞增的事務 Id 來標識,所有的 proposal(提議)都在被提出的時候加上了 zxid,zxid 實際
上是一個 64 位的數字,高 32 位是 epoch(時期; 紀元; 世; 新時代)用來標識 leader 是否發生改變,如果有
新的 leader 產生出來,epoch 會自增,低 32 位用來遞增計數。當新產生 proposal 的時候,會依據數據庫的
兩階段過程,首先會向其他的 server 發出事務執行請求,如果超過半數的機器都能執行並且能夠成功,那麼就
會開始執行。

16.Zookeeper 下 Server 工作狀態
每個 Server 在工作過程中有三種狀態:
LOOKING:當前 Server 不知道 leader 是誰,正在搜尋
LEADING:當前 Server 即爲選舉出來的 leader
FOLLOWING:leader 已經選舉出來,當前 Server 與之同步

17.zookeeper 是如何選取主 leader 的?
當 leader 崩潰或者 leader 失去大多數的 follower,這時 zk 進入恢復模式,恢復模式需要重新選舉出一個新的
leader,讓所有的 Server 都恢復到一個正確的狀態。Zk 的選舉算法有兩種:一種是基於 basic paxos 實現
的,另外一種是基於 fast paxos 算法實現的。系統默認的選舉算法爲 fast paxos。 1、Zookeeper 選主流程(basic paxos)
(1)選舉線程由當前 Server 發起選舉的線程擔任,其主要功能是對投票結果進行統計,並選出推薦的
Server; (2)選舉線程首先向所有 Server 發起一次詢問(包括自己); (3)選舉線程收到回覆後,驗證是否是自己發起的詢問(驗證 zxid 是否一致),然後獲取對方的 id(myid),並存
儲到當前詢問對象列表中,最後獲取對方提議的 leader 相關信息(id,zxid),並將這些信息存儲到當次選舉的投
票記錄表中;
(4)收到所有 Server 回覆以後,就計算出 zxid 最大的那個 Server,並將這個 Server 相關信息設置成下一次
要投票的 Server; (5)線程將當前 zxid 最大的 Server 設置爲當前 Server 要推薦的 Leader,如果此時獲勝的 Server 獲得 n/2

  • 1 的 Server 票數,設置當前推薦的 leader 爲獲勝的 Server,將根據獲勝的 Server 相關信息設置自己的狀
    態,否則,繼續這個過程,直到 leader 被選舉出來。 通過流程分析我們可以得出:要使 Leader 獲得多數
    Server 的支持,則 Server 總數必須是奇數 2n+1,且存活的 Server 的數目不得少於 n+1. 每個 Server 啓動後
    都會重複以上流程。在恢復模式下,如果是剛從崩潰狀態恢復的或者剛啓動的 server 還會從磁盤快照中恢復數
    據和會話信息,zk 會記錄事務日誌並定期進行快照,方便在恢復時進行狀態恢復。
    2、Zookeeper 選主流程(basic paxos)
    fast paxos 流程是在選舉過程中,某 Server 首先向所有 Server 提議自己要成爲 leader,當其它 Server 收到提
    議以後,解決 epoch 和 zxid 的衝突,並接受對方的提議,然後向對方發送接受提議完成的消息,重複這個流
    程,最後一定能選舉出 Leader。
    18.Zookeeper 同步流程
    選完 Leader 以後,zk 就進入狀態同步過程。
    1、Leader 等待 server 連接;
    2、Follower 連接 leader,將最大的 zxid 發送給 leader; 3、Leader 根據 follower 的 zxid 確定同步點;
    4、完成同步後通知 follower 已經成爲 uptodate 狀態;
    5、Follower 收到 uptodate 消息後,又可以重新接受 client 的請求進行服務了。
    19.分佈式通知和協調
    對於系統調度來說:操作人員發送通知實際是通過控制檯改變某個節點的狀態,然後 zk 將這些變化發送給註冊
    了這個節點的 watcher 的所有客戶端。
    對於執行情況彙報:每個工作進程都在某個目錄下創建一個臨時節點。並攜帶工作的進度數據,這樣彙總的進
    程可以監控目錄子節點的變化獲得工作進度的實時的全局情況。
    20.機器中爲什麼會有 leader?
    在分佈式環境中,有些業務邏輯只需要集羣中的某一臺機器進行執行,其他的機器可以共享這個結果,這樣可
    以大大減少重複計算,提高性能,於是就需要進行 leader 選舉。
    21.zk 節點宕機如何處理?
    Zookeeper 本身也是集羣,推薦配置不少於 3 個服務器。Zookeeper 自身也要保證當一個節點宕機時,其他
    節點會繼續提供服務。
    如果是一個 Follower 宕機,還有 2 臺服務器提供訪問,因爲 Zookeeper 上的數據是有多個副本的,數據並不
    會丟失;
    如果是一個 Leader 宕機,Zookeeper 會選舉出新的 Leader。
    ZK 集羣的機制是隻要超過半數的節點正常,集羣就能正常提供服務。只有在 ZK 節點掛得太多,只剩一半或不
    到一半節點能工作,集羣才失效。
    所以
    3 個節點的 cluster 可以掛掉 1 個節點(leader 可以得到 2 票>1.5)
    2 個節點的 cluster 就不能掛掉任何 1 個節點了(leader 可以得到 1 票<=1)
    22.zookeeper 負載均衡和 nginx 負載均衡
    區別
    zk 的負載均衡是可以調控,nginx 只是能調權重,其他需要可控的都需要自己寫插件;但是 nginx 的吞吐量比
    zk 大很多,應該說按業務選擇用哪種方式。
    23.zookeeper watch 機制
    Watch 機制官方聲明:一個 Watch 事件是一個一次性的觸發器,當被設置了 Watch 的數據發生了改變的時
    候,則服務器將這個改變發送給設置了 Watch 的客戶端,以便通知它們。
    Zookeeper 機制的特點:
    1、一次性觸發數據發生改變時,一個 watcher event 會被髮送到 client,但是 client 只會收到一次這樣的信
    息。2、watcher event 異步發送 watcher 的通知事件從 server 發送到 client 是異步的,這就存在一個問題,不同
    的客戶端和服務器之間通過 socket 進行通信,由於網絡延遲或其他因素導致客戶端在不通的時刻監聽到事件,
    由於 Zookeeper 本身提供了 ordering guarantee,即客戶端監聽事件後,纔會感知它所監視 znode 發生了
    變化。所以我們使用 Zookeeper 不能期望能夠監控到節點每次的變化。Zookeeper 只能保證最終的一致性,
    而無法保證強一致性。 3、數據監視 Zookeeper 有數據監視和子數據監視 getdata() and exists()設置數據監視,getchildren()設置了
    子節點監視。
    4、註冊 watcher getData、exists、getChildren
    5、觸發 watcher create、delete、setData
    6、setData()會觸發 znode 上設置的 data watch(如果 set 成功的話)。一個成功的 create() 操作會觸發被
    創建的 znode 上的數據 watch,以及其父節點上的 child watch。而一個成功的 delete()操作將會同時觸發一
    個 znode 的 data watch 和 child watch(因爲這樣就沒有子節點了),同時也會觸發其父節點的 child
    watch。 7、當一個客戶端連接到一個新的服務器上時,watch 將會被以任意會話事件觸發。當與一個服務器失去連接的
    時候,是無法接收到 watch 的。而當 client 重新連接時,如果需要的話,所有先前註冊過的 watch,都會被重
    新註冊。通常這是完全透明的。只有在一個特殊情況下,watch 可能會丟失:對於一個未創建的 znode 的
    exist watch,如果在客戶端斷開連接期間被創建了,並且隨後在客戶端連接上之前又刪除了,這種情況下,這
    個 watch 事件可能會被丟失。
    8、Watch 是輕量級的,其實就是本地 JVM 的 Callback,服務器端只是存了是否有設置了 Watcher 的布爾類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章