Kafka的broker數(shù)據(jù)同步(高水位與Epoch)

前言

Kafka的broker端有ISR機制,它可以看成多個副本的集合,里面有l(wèi)eader副本和多個follower副本,數(shù)量是我們可以配置的,只有ISR中的副本才有可能成為leader副本。
我們可以通過一些參數(shù)的配置,例如ack的配置、生產(chǎn)者重試、isr最小數(shù)量,消費者改為手動提交等方式來盡可能的保障Kafka的消息可靠性。
Kafka在保證數(shù)據(jù)的可靠性上使用的是‘數(shù)據(jù)冗余’的方式,即將一個分區(qū)下的數(shù)據(jù)保存到多個副本中,起到備份數(shù)據(jù)的作用。這樣如果leader掛了,會重新選舉follower作為leader繼續(xù)工作,那么Kafka中l(wèi)eader副本是如何將數(shù)據(jù)同步到follower副本中的呢?


broker里的高水位(High Watermark)

什么是高水位?

在Kafka中,高水位是一個位置信息標記,它是用消息位移來表征的,比如某個副本中HW=8,就是這個副本的高水位在offset=8那個位置上。

image.png

還有一個日志末端位移的概念,Log End Offset,縮寫是LEO。它表示副本寫入下一條消息的位移值。上圖中LEO是15,即下一條新消息的位移是15,8-14這些位置上的消息就是未提交消息。同一個副本對象,其高水位值不會大于LEO值。

HW的作用

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

  1. 定義消息的可見性,即用來標識分區(qū)下的哪些消息是可以被消費的,比如某個分區(qū)的HW(leader的HW)是8,那么這個分區(qū)只有 < 8 這些位置上消息可以被消費。即高水位之前的消息才被認為是已提交的消息,才可以被消費。
  2. 幫助Kafka完成副本同步。

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

分區(qū)的高水位就是其leader副本的高水位。

副本同步機制解析

首先我們先看一個例子:

開始時,follower向leader副本發(fā)送fetch同步數(shù)據(jù)請求,此時他們的HW和LEO都是0。


image.png

當生產(chǎn)者向leader發(fā)送一條消息,且提交成功后,leader的LEO更新為1,這個時候follower發(fā)現(xiàn)有消息可以拉取了,于是follower的LEO也更新為1,但是此時leader和follower的HW都為0,它們需要在下一輪的拉取中被更新。


image.png

在新一輪的拉取請求中,因為之前位移值是0的消息已經(jīng)拉取成功了,所以follower這次請求拉取的是位移值=1的消息。leader接收到這個請求后,將遠程副本LEO更新為1,然后更新leader的HW=1,最后將HW=1發(fā)送給follower副本,follower收到后將自己的高水位值更新成1。


image.png

至此,一次完整的消息同步周期就結(jié)束了。Kafka就是利用這樣的機制,實現(xiàn)了leader和follower之前的同步。

這里看高水位機制,有點像分布式事務的二次提交。

依托于高水位,Kafka既界定了消息的對外可見性,又實現(xiàn)了異步的副本同步機制。但是這里面還存在一些問題。剛才我們了解到的Kafka副本同步的過程中,follower副本的高水位更新需要一輪額外的拉取請求才能實現(xiàn)。如果有多個follower副本,情況可能更糟,就需要多輪拉取請求。也就是說,leader副本的高水位更新和follower副本高水位更新在時間上是存在一定延遲的,這樣會導致數(shù)據(jù)丟失或者數(shù)據(jù)不一致。

我們再來看下數(shù)據(jù)丟失的場景:
  1. 數(shù)據(jù)丟失
    下圖中,副本A是leader,副本B是follower,現(xiàn)在情況是A的LEO和HW都是2,副本B中的LEO也更新成了2,但是HW還是1,它需要再一輪請求來更新自己的HW,但是此時因為某些原因,B重啟了,重啟完后,B會執(zhí)行日志截斷功能,將LEO調(diào)整到它的高水位位置,即副本B的LEO變?yōu)榱?,就是說副本B中位置為1的消息被刪除了,現(xiàn)在只有0一條消息了。


    image.png

執(zhí)行完截斷操作后,副本B開始從A拉取消息,執(zhí)行正常的消息同步。如果在這個時候,副本A所在的Broker宕機了,那么kafka只能選B成為新的leader了,當A重啟回來后,需要執(zhí)行相同的日志截斷工作,將高水位調(diào)整為B的高水位值,因為規(guī)定follower的HW值不能超過leader中的HW值。A中的位移1位置的消息也被刪除了,這樣這條消息就丟失了。

image.png

  1. 數(shù)據(jù)不一致
    上圖中副本A和B,其中副本A中有兩條消息,LEO是2、HW是2,B的LEO和HW都是1,假設(shè)在同一時刻,A和B都宕機了,然后B先醒過來,那么B成了新的leader,然后他收到生產(chǎn)者發(fā)來的m3消息,然后B的LEO和HW都更新成了2。
    當A醒過來后,會先根據(jù)HW判斷是否需要進行日記截斷,這里HW和LEO相等,發(fā)現(xiàn)不需要進行日志截斷,然后跟B進行同步,這個時候A和B的LEO都是2,這樣A中的消息是<m1,m2>,B中的消息是<m1,m3>,出現(xiàn)了消息不一致的情況。

Leader Epoch是什么

Leader Epoch 可以認為是leader的版本,它由兩部分數(shù)據(jù)組成。(這里kafka應該是借鑒了zk的數(shù)據(jù)同步機制ZAB)

  1. Epoch,一個單調(diào)增加的版本號。每當副本領(lǐng)導權(quán)發(fā)生變更后,都會增加該版本號。小版本號的leader被認定是過期leader。
  2. 起始位移,leader副本在該Epoch值上寫入的首條消息的位移。

假設(shè)現(xiàn)在有兩個 Leader Epoch<0, 0> 和 <1, 120>,那么,第一個 Leader Epoch 表示版本號是 0,這個版本的 Leader 從位移 0 開始保存消息,一共保存了 120 條消息。之后,Leader 發(fā)生了變更,版本號增加到 1,新版本的起始位移是 120。

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

Leader Epoch是如何解決消息丟失和消息不一致的問題的

消息丟失
image.png

還是剛才那個場景,現(xiàn)在有了Leader Epoch機制的介入,當副本B重啟回來后,會向A發(fā)送一個請求去獲取leader中的LEO,發(fā)現(xiàn)A的LEO=2,不比它自己的LEO值小,而且緩存中沒有保存任何起始位移值 > 2的Epoch條目,這樣B就不需要執(zhí)行日志截斷操作了。
然后副本A宕機了,B成為了leader,B的Leader Epoch由原來的<0, 0> 更新成了 <1, 2>,意思說是B成為了新的leader,版本號+1,這個leader的起始消息位移值為2。
A重啟回來后會向B發(fā)送請求獲取B的LEO,發(fā)現(xiàn)等于2,和自己相同,并且緩存中的Leader Epoch的起始位移值是2,也不需要進行日志截斷。這樣就不會出現(xiàn)消息丟失的問題了。

消息不一致

有了Leader Epoch機制的加入,當B變?yōu)閘eader后,producer發(fā)送m3消息到B中,數(shù)據(jù)保存到磁盤上,Leader Epoch會更新為<1,2>,然后A醒過來后,會先發(fā)送請求知道B的LEO值為2和自己一樣,然后通過緩存的Leader Epoch值,得知下一條要寫入的消息是1的位置,然后就會進行日志截斷,將原先的m2刪除,再將m3寫入。由此解決了消息不一致的問題。

思考

  • 這里為什么高水位的時候,副本B重啟要截斷offset=1的數(shù)據(jù),而引入epoch后,就不需要截斷了(這也是消息丟失問題所在)?

設(shè)計者角度思考下,沒有引入epoch的時候,副本B重啟發(fā)現(xiàn)HW與LEO不一致,它并不知道其間的數(shù)據(jù),是不是當前l(fā)eader同步來的,并不確定是否和當前l(fā)eader的數(shù)據(jù)一致(只有HW以前的才能保證是與leader同步好的)
引入epoch后,可以判斷當前l(fā)eader的epoch-offset位后的數(shù)據(jù)都是當前l(fā)eader的數(shù)據(jù)(這里再想下,如果副本B的HW是更前的offset,超過了當前l(fā)eader的epoch-offset位時要怎樣?這里就會截斷,然后同步當前l(fā)eader的副本B的HW位后的所有數(shù)據(jù))

  • 消息不一致的問題

同樣也是會判斷當前重啟的broker,看最新leader的epoch-offset,看是否與本身的HW位有交叉,如果有,那需要與新leader同步數(shù)據(jù),截斷新leader的epoch-offset后的數(shù)據(jù)(因為這部分不是老leader寫入的)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內(nèi)容