每個kafka副本對象都持有2個重要的屬性:日志末端位移LEO,高水印HW
Kafka對leader副本和follower副本的LEO更新機制是不同的,后面我們會詳細討論。
Kafka對leader副本和follower副本的hw值更新機制也是不同的。
消費者無法消費分區leader副本上那些位移大於分區hw的消息。分區hw就是leader副本的hw值。
關於LEO
2套follower副本LEO屬性:一套LEO值保存在follower副本所在broker的緩存上;另一套LEO值保存在leader副本所在的broker的緩存上。
follwer副本的LEO:每寫一條消息就+1
leader上的副本LEO:收到FETCH請求之后,先從自己的log中讀取相應的數據,但是在給follower返回數據之前它先去更新follower的LEO
關於HW(時機+算法)
follower更新hw:follower更新hw發生在其更新LEO之后,一旦follower向log寫完數據,它就會嘗試更新HW值,具體的算法就是比較當前LEO值與FETCH響應中leader的HW值,取兩者的小者作為新的HW值。
leader更新hw的時機:
1.副本成為leader時
2.broker出現崩潰導致副本被踢出ISR時
3.producer向leader副本寫入消息時
4.leader處理followerFETCH請求時:首先會從底層的log讀取數據,之后再嘗試更新分區HW值。
如何更新:
當確定分區hw時,它會選出所有滿足條件的副本,比較他們的LEO,並選擇最小的LEO值作為HW值,這里的滿足條件主要是指副本滿足一下兩個條件之一:
1.出於ISR中
2.副本LEO落后於leaderLEO的時長不大於replica.lag.time.max.ms參數值(默認時10秒)
特殊情況:
Hw值的更新通常需要另一輪FETCH請求才能完成,故這種設計在本質上是存在缺陷的。可能引起,備份數據丟失,備份數據不一致。
fetch請求沒有新消息時返回什么?leader會更新leo嗎。答:follower發送過來的FETCH請求因為無數據而暫時被寄存到leader端的purgatory中,待500毫秒后超時會強制完成。
leader宕機時hw之外的消息會丟失?
hw在第二輪剛開始的時候宕機,新leader的沒更新hw,這個時候它本地沒有LEO,怎么更新hw。 是不是需要一輪其他副本fetch請求之后才能確定hw,和生成本地leo緩存。
基於·水印備份機制的缺陷:hw過期
在0.11.0.0版本之前,kafka一直使用基於水印的備份機制
1.數據丟失
前提:min.insync.replicas=1
follower副本在重啟后將leo截斷至hw(為什么要截斷)。此時在給leader發FETCH,若leader此時宕機那么被截斷的那部分就丟失了.
2.數據不一致/數據離散
前提:min.insync.replicas=1
A leo=2 hw=2,B leo=1 hw=1;AB同時掛掉,B先重連並且寫入一條消息hw=2,A再重啟后發現hw與分區相同,會不作調整繼續工作。
0.11.0.0版本解決之道
leader epoch取代hw,leader端多開辟一段內存區域專門保存leader的epoch信息。
所謂leader epoch,實際上是一對值,epoch表示leader的版本號,從0開始,當leader變更過1次,epoch就會加1,而offset則對應與該epoch版本的leader寫入第一條消息的位移,假設存在兩對值(0,0)和(1,120)那么表示第一個leader從位移0開始寫入消息,供血了120條。
每個leader broker中會保存這樣一個緩存,並定期寫入一個檢查點文件中,當leader寫滴成log時,它會嘗試更新整個緩存--如果這個leader首次寫消息,則會在緩存中增加一個條目,否則就不做更新,而每次副本重新成為leader時會查詢這部分混存,獲取對應leader版本的位移,這就不會發生數據不一致和丟失的情況。
這里offsetsForLeaderEpochRequest如果A在響應之前就宕機了怎么辦