04、關于高水位和Leader Epoch

在 Kafka 中,高水位的作用主要有 2 個。

  1. 定義消息可見性,即用來標識分區下的哪些消息是可以被消費者消費的。
  2. 幫助 Kafka 完成副本同步。

下面這張圖展示了多個與高水位相關的 Kafka 術語。我來詳細解釋一下圖中的內容,同時澄清一些常見的誤區。


位移值等于高水位的消息也屬于未提交消息。也就是說,高水位上的消息是不能被消費者消費的。

Log End Offset,簡寫是 LEO。它表示副本寫入下一條消息的位移值。

介于高水位和 LEO 之間的消息就屬于未提交消息。這也從側面告訴了我們一個重要的事實,那就是:同一個副本對象,其高水位值不會大于 LEO 值。



什么叫與 Leader 副本保持同步。判斷的條件有兩個。

  1. 該遠程 Follower 副本在 ISR 中。
  2. 該遠程 Follower 副本 LEO 值落后于 Leader 副本 LEO 值的時間,不超過 Broker 端參數 replica.lag.time.max.ms 的值。如果使用默認值的話,就是不超過 10 秒

副本同步機制解析

當生產者發送一條消息時,Leader 和 Follower 副本對應的高水位是怎么被更新的呢?我給出了一些圖片,我們一一來看。

首先是初始狀態。下面這張圖中的 remote LEO 就是剛才的遠程副本的 LEO 值。在初始狀態時,所有值都是 0。

當生產者給主題分區發送一條消息后,狀態變更為:

此時,Leader 副本成功將消息寫入了本地磁盤,故 LEO 值被更新為 1。

Follower 再次嘗試從 Leader 拉取消息。和之前不同的是,這次有消息可以拉取了,因此狀態進一步變更為:

這時,Follower 副本也成功地更新 LEO 為 1。此時,Leader 和 Follower 副本的 LEO 都是 1,但各自的高水位依然是 0,還沒有被更新。它們需要在下一輪的拉取中被更新,如下圖所示:

在新一輪的拉取請求中,由于位移值是 0 的消息已經拉取成功,因此 Follower 副本這次請求拉取的是位移值 =1 的消息。Leader 副本接收到此請求后,更新遠程副本 LEO 為 1,然后更新 Leader 高水位為 1。做完這些之后,它會將當前已更新過的高水位值 1 發送給 Follower 副本。Follower 副本接收到以后,也將自己的高水位值更新成 1。至此,一次完整的消息同步周期就結束了。事實上,Kafka 就是利用這樣的機制,實現了 Leader 和 Follower 副本之間的同步。

Leader Epoch 登場

我們知道,Follower 副本的高水位更新需要一輪額外的拉取請求才能實現。如果把上面那個例子擴展到多個 Follower 副本,情況可能更糟,也許需要多輪拉取請求。也就是說,Leader 副本高水位更新和 Follower 副本高水位更新在時間上是存在錯配的。這種錯配是很多“數據丟失”或“數據不一致”問題的根源。基于此,社區在 0.11 版本正式引入了 Leader Epoch 概念,來規避因高水位更新錯配導致的各種不一致問題。

所謂 Leader Epoch,我們大致可以認為是 Leader 版本。它由兩部分數據組成。

  1. Epoch。一個單調增加的版本號。每當副本領導權發生變更時,都會增加該版本號。小版本號的 Leader 被認為是過期 Leader,不能再行使 Leader 權力。
  2. 起始位移(Start Offset)。Leader 副本在該 Epoch 值上寫入的首條消息的位移。

我舉個例子來說明一下 Leader Epoch。假設現在有兩個 Leader Epoch<0, 0> 和 <1, 120>,那么,第一個 Leader Epoch 表示版本號是 0,這個版本的 Leader 從位移 0 開始保存消息,一共保存了 120 條消息。之后,Leader 發生了變更,版本號增加到 1,新版本的起始位移是 120。

Kafka Broker 會在內存中為每個分區都緩存 Leader Epoch 數據,同時它還會定期地將這些信息持久化到一個 checkpoint 文件中。當 Leader 副本寫入消息到磁盤時,Broker 會嘗試更新這部分緩存。如果該 Leader 是首次寫入消息,那么 Broker 會向緩存中增加一個 Leader Epoch 條目,否則就不做更新。這樣,每次有 Leader 變更時,新的 Leader 副本會查詢這部分緩存,取出對應的 Leader Epoch 的起始位移,以避免數據丟失和不一致的情況。

接下來,我們來看一個實際的例子,它展示的是 Leader Epoch 是如何防止數據丟失的。請先看下圖。

我稍微解釋一下,單純依賴高水位是怎么造成數據丟失的。開始時,副本 A 和副本 B 都處于正常狀態,A 是 Leader 副本。某個使用了默認 acks 設置的生產者程序向 A 發送了兩條消息,A 全部寫入成功,此時 Kafka 會通知生產者說兩條消息全部發送成功。

現在我們假設 Leader 和 Follower 都寫入了這兩條消息,而且 Leader 副本的高水位也已經更新了,但 Follower 副本高水位還未更新——這是可能出現的。還記得吧,Follower 端高水位的更新與 Leader 端有時間錯配。倘若此時副本 B 所在的 Broker 宕機,當它重啟回來后,副本 B 會執行日志截斷操作,將 LEO 值調整為之前的高水位值,也就是 1。這就是說,位移值為 1 的那條消息被副本 B 從磁盤中刪除,此時副本 B 的底層磁盤文件中只保存有 1 條消息,即位移值為 0 的那條消息。

當執行完截斷操作后,副本 B 開始從 A 拉取消息,執行正常的消息同步。如果就在這個節骨眼上,副本 A 所在的 Broker 宕機了,那么 Kafka 就別無選擇,只能讓副本 B 成為新的 Leader,此時,當 A 回來后,需要執行相同的日志截斷操作,即將高水位調整為與 B 相同的值,也就是 1。這樣操作之后,位移值為 1 的那條消息就從這兩個副本中被永遠地抹掉了。這就是這張圖要展示的數據丟失場景。

嚴格來說,這個場景發生的前提是Broker 端參數 min.insync.replicas 設置為 1。此時一旦消息被寫入到 Leader 副本的磁盤,就會被認為是“已提交狀態”,但現有的時間錯配問題導致 Follower 端的高水位更新是有滯后的。如果在這個短暫的滯后時間窗口內,接連發生 Broker 宕機,那么這類數據的丟失就是不可避免的。

現在,我們來看下如何利用 Leader Epoch 機制來規避這種數據丟失。我依然用圖的方式來說明。

場景和之前大致是類似的,只不過引用 Leader Epoch 機制后,Follower 副本 B 重啟回來后,需要向 A 發送一個特殊的請求去獲取 Leader 的 LEO 值。在這個例子中,該值為 2。當獲知到 Leader LEO=2 后,B 發現該 LEO 值不比它自己的 LEO 值小,而且緩存中也沒有保存任何起始位移值 > 2 的 Epoch 條目,因此 B 無需執行任何日志截斷操作。這是對高水位機制的一個明顯改進,即副本是否執行日志截斷不再依賴于高水位進行判斷。

現在,副本 A 宕機了,B 成為 Leader。同樣地,當 A 重啟回來后,執行與 B 相同的邏輯判斷,發現也不用執行日志截斷,至此位移值為 1 的那條消息在兩個副本中均得到保留。后面當生產者程序向 B 寫入新消息時,副本 B 所在的 Broker 緩存中,會生成新的 Leader Epoch 條目:[Epoch=1, Offset=2]。之后,副本 B 會使用這個條目幫助判斷后續是否執行日志截斷操作。這樣,通過 Leader Epoch 機制,Kafka 完美地規避了這種數據丟失場景。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,237評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,205評論 2 375