面試官:zookeeper集羣的leader掛了怎麼辦

某天程序員小白參加面試:

幾番苦戰之後,面試進入白熱化階段。面試官大開大合,小白見招拆招。一時之間,難解難分,兩人對拆數十回合不分勝負。說時遲,那時快,小白的左手像火焰一般炙熱,右手像冰霜一樣寒冷…
萬萬沒想到

面試官:我看你簡歷上寫了熟悉zookeeper,你項目裏用zookeeper幹什麼了?

小白:主要用來做dubbo的註冊中心、分佈式鎖以及統一配置等

面試官:那你熟悉zookeeper集羣模型嗎?

小白:zookeeper集羣是一主多從的模型,節點分成三種角色:leader、follower和observer。leader負責寫、follower和observer負責讀。
(小白內心:面試官接下來該問我follower和observer的區別了)

面試官:你說zookeeper是一主多從,那麼主掛掉了怎麼辦(單點故障)?

(小白內心:我勒個擦,怎麼不按套路出牌。記得redis主從複製模型中,master掛掉之後是靠sentinel自動完成故障轉移的。zookeeper好像沒有sentinel…不過這可難不倒我)
小白:我們系統的zookeeper非常穩定,leader不會掛

面試官
目瞪狗呆

前置閱讀

可靠性

從zookeeper官網上的描述可以知道,zookeeper自稱是高可用的,像這種自帶高可用的中間件可不多見。zookeeper一主多從的模型,leader只有一個,註定會成爲單點故障。

leader掛了不可怕,可怕的是沒有leader。古代皇帝駕崩之後,大臣通常會說這樣一句話:國不可一日無君,然後勸太子早承大統。

zookeeper的做法也是一樣,就是盡最快的速度,從存活的follower中選出一個新leader。那麼現在問題來了,皇帝駕崩之前往往已經立了太子,或者由嫡長子自動繼承。但是對zookeeper來說,不可能提前選好下一個預備leader,並且follower之間也沒有嫡庶之分,換言之,每個follower的身份都是平等的。

zookeeper採用了ZAB算法來解決選舉的問題。

ZAB

ZAB(Zookeeper Atomic Broadcast,zookeeper原子廣播),ZAB協議用來保證zookeeper各個節點之間數據的一致性。

ZAB協議包括如下特點:

  • follower節點上所有的寫請求都轉發給leader
  • 寫操作嚴格有序
  • ZooKeeper使用改編的兩階段提交協議來保證各個節點的事務一致性

兩階段提交

二階段提交(英語:Two-phase Commit)是指在計算機網絡以及數據庫領域內,爲了使基於分佈式系統架構下的所有節點在進行事務提交時保持一致性而設計的一種算法。通常,二階段提交也被稱爲是一種協議(Protocol)。在分佈式系統中,每個節點雖然可以知曉自己的操作時成功或者失敗,卻無法知道其他節點的操作的成功或失敗。當一個事務跨越多個節點時,爲了保持事務的ACID特性,需要引入一個作爲協調者的組件來統一掌控所有節點(稱作參與者)的操作結果並最終指示這些節點是否要把操作結果進行真正的提交(比如將更新後的數據寫入磁盤等等)。因此,二階段提交的算法思路可以概括爲: 參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。

兩階段提交就是把提交分成2個階段。預提交階段和提交階段
2階段提交
整個提交過程分爲4個步驟

  • 協調者詢問所有的參與者是不是可以提交了
  • 參與者回覆yes or no
  • 協調者收到所有的yes之後執行commit否則執行rollback
  • 參與者執行完成後回覆ACK

zookeeper採用的是改編過的兩階段提交,就是在第三步的時候,不需要所有的參與者回覆yes,只需要超過半數(剛好半數也不行)的參與者回覆yes。之所以是超過半數而不是所有參與者回覆yes,是爲了避免少量的參與者出現單點故障或者網絡波動導致協調者長時間收不到回覆。

zookeeper集羣的狀態分爲兩種:正常狀態異常狀態。也就是有leader(能提供服務)和沒有leader(進入選舉)

廣播模式

廣播模式就是指zookeeper正常工作的模式。正常情況下,一個寫入命令會經過如下步驟被執行

  • leader從客戶端或者follower那裏收到一個寫請求
  • leader生成一個新的事務併爲這個事務生成一個唯一的Zxid
  • leader將這個事務發送給所有的follows節點
  • follower節點將收到的事務請求加入到歷史隊列(history queue)中,併發送ack給leader
  • 當leader收到大多數follower(超過法定數量)的ack消息,leader會發送commit請求
  • 當follower收到commit請求時,會判斷該事務的Zxid是不是比歷史隊列中的任何事務的Zxid都小,如果是則commit,如果不是則等待比它更小的事務的commit

恢復模式

當leader故障之後,zookeeper集羣進入無主模式,此時zookeeper集羣不能對外提供服務,必須選出一個新的leader完成數據一致後才能重新對外提供服務。zookeeper官方宣稱集羣可以在200毫秒內選出一個新leader。

正常模式下的幾個步驟,每個步驟都有可能因爲leader故障而中斷。但是恢復過程只與leader有沒有commit有關。

首先看前三個步驟,只做了一件事,把事務發送出去。

如果事務沒有發出去,所有follower都沒有收到這個事務,leader故障了。所有的follower都不知道這個事務的存在,根據心跳檢測機制,follower發現leader故障,重新選出一個leader。會根據每個節點Zxid來選擇,誰的Zxid最大,表示誰的數據最新,自然會被選舉成新的leader。如果Zxid都一樣,表示在follower故障之前,所有的follower節點數據完全一致,此時選擇myid最大的節點成爲新的leader,因爲有一個固定的選舉標準會加快選舉流程。新的leader選出來之後,所有節點的數據本身就是一致的,此時就可以對外提供服務。

假設新的leader選出來之後,原來的leader又恢復了,此時原來的leader會自動成爲follower,之前的事務即使重新發送給新的leader,因爲新的leader已經開啓了新的紀元,而原先的leader中Zxid還是舊的紀元,自然會被丟棄。並且該節點的Zxid也會更新成新的紀元。

紀元的意思就是標識當前leader是第幾任leader,相當於改朝換代時候的年號

如果在leader故障之前已經commit,zookeeper依然會根據Zxid或者myid選出數據最新的那個follower作爲新的leader。新leader與follower建立FIFO的隊列, 先將自身有而follower缺失的事務發送給它,再將這些事務的commit命令發送給 follower,這便保證了所有的follower都保存了所有的事務、所有的follower都處理了所有的消息。

ZAB 協議確保那些已經在 Leader 提交的事務最終會被所有服務器提交。
ZAB 協議確保丟棄那些只在 Leader 提出/複製,但沒有提交的事務。

總結

本文單單從zookeeper的角度解釋了主從模式的數據一致性,而沒有寫paxos和ZAB算法中的一些概念。因爲paxos算法確實難以理解,網上關於paxos算法的講解也多如黃河之沙。並且關於paxos和zab,不同的人有不同的見解。若有興趣,可自行查閱,博主就不誤人子弟了。

參考

  • https://zh.wikipedia.org/zh-hans/二階段提交
  • https://mp.weixin.qq.com/s/AE_2U5tUjEZSYoLovlcU6g
  • https://zookeeper.apache.org/doc/r3.4.11/zookeeperInternals.html

擴展閱讀

  • https://zh.wikipedia.org/zh-cn/Paxos算法
  • https://www.douban.com/note/208430424/
  • https://www.bilibili.com/video/BV1TW411M7Fx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章