文章目錄
為保證producer發送的數據,能可靠的發送到指定的topic,topic的每個partition收到producer發送的數據后,都需要向producer發送ack(acknowledgement確認收到),如果producer收到ack,就會進行下一輪的發送,否則重新發送數據。
1.副本數據同步策略
方案 | 優點 | 缺點 |
---|---|---|
半數以上follower完成同步,就發送ack | 延遲低(follower同步有快有慢,半數以上同步完成就發送ack能把滿的那些給過濾掉) | 選舉新的leader時,容忍n台節點的故障,需要2n+1個副本(半數以上參與投票表示需要n+1台節點存活,總共則需要n+1+n個副本) |
全部的follower完成同步,才發送ack | 選舉新的leader時,容忍n台節點的故障,需要n+1個副本 | 延遲高(同步快的需要等同步滿的,導致延遲高) |
Kafka選擇了第二種方案(全部完成同步,才發送ack),原因如下:
- 同樣為了容忍n台節點的故障,第一種方案需要2n+1個副本,而第二種方案只需要n+1個副本,而Kafka的每個分區都有大量的數據,第一種方案會造成大量數據的冗余。
- 雖然第二種方案的網絡延遲會比較高,但網絡延遲對Kafka的影響較小。
2.ISR,AR
采用第二種方案之后,設想以下情景:leader收到數據,所有follower都開始同步數據,但有一個follower,因為某種故障,遲遲不能與leader進行同步,那leader就要一直等下去,直到它完成同步,才能發送ack。這個問題怎么解決呢?
Leader維護了一個動態的in-sync replica set (ISR-同步副本列表),意為和leader保持同步的follower集合。當ISR中的follower完成數據的同步之后,leader就會給follower發送ack。如果follower長時間未向leader同步數據,則該follower將被踢出ISR,該時間閾值由replica.lag.time.max.ms
參數設定。Leader發生故障之后,就會從ISR中選舉新的leader。
-
ISR(In-Sync Replicas ):與leader保持同步的follower集合
-
AR(Assigned Replicas):分區的所有副本
ISR是由leader維護,follower從leader同步數據有一些延遲(包括延遲時間replica.lag.time.max.ms和延遲條數replica.lag.max.messages兩個維度, 當前最新的版本0.10.x中只支持replica.lag.time.max.ms這個維度),任意一個超過閾值都會把follower剔除出ISR, 存入**OSR(Outof-Sync Replicas)**列表,新加入的follower也會先存放在OSR中。AR=ISR+OSR。
3.ack應答機制
對於某些不太重要的數據,對數據的可靠性要求不是很高,能夠容忍數據的少量丟失,所以沒必要等ISR中的follower全部接收成功。
所以Kafka為用戶提供了三種可靠性級別,用戶根據對可靠性和延遲的要求進行權衡,選擇以下的配置。
acks參數配置:
-
0:producer不等待broker的ack,這一操作提供了一個最低的延遲,broker一接收到還沒有寫入磁盤就已經返回,當broker故障時有可能丟失數據;
-
1:producer等待broker的ack,partition的leader落盤成功后返回ack,如果在follower同步成功之前leader故障,而由於已經返回了ack,系統默認新選舉的leader已經有了數據,從而不會進行失敗重試,那么將會丟失數據
-
-1(all):producer等待broker的ack,partition的leader和follower全部落盤成功后才返回ack。但是如果在follower同步完成后,broker發送ack之前,leader發生故障,導致沒有返回ack給Producer,由於失敗重試機制,又會給新選舉出來的leader發送數據,造成數據重復。
4. HW,LEO,LSO,LW名詞解釋
上圖表示一個日志文件,這個日志文件中只有9條消息,第一條消息的offset(LogStartOffset)為0,最后一條消息的offset為8,offset為9的消息使用虛線表示的,代表下一條待寫入的消息。日志文件的 HW 為6,表示消費者只能拉取offset在 0 到 5 之間的消息,offset為6的消息對消費者而言是不可見的。
-
LEO(log end offset):標識當前日志文件中已寫入消息的最后一條的下一條待寫入的消息的offset。上圖中offset為9的位置即為當前日志文件的 LEO,LEO 的大小相當於當前日志分區中最后一條消息的offset值加1.分區 ISR 集合中的每個副本都會維護自身的 LEO ,而 ISR 集合中最小的 LEO 即為分區的 HW,對消費者而言只能消費 HW 之前的消息。
-
HW(High Watermark):所有副本中最小的LEO, 一個分區中所有副本最小的offset,取一個partition對應的ISR中最小的LEO作為HW,consumer最多只能消費到HW所在的位置上一條信息。
注意:HW/LEO這兩個都是指已寫入消息的最后一條的下一條的位置而不是指最后一條的位置。
-
LSO(Last Stable Offset): 對未完成的事務而言,LSO 的值等於事務中第一條消息的位置(firstUnstableOffset),對已完成的事務而言,它的值同 HW 相同
-
LW(Low Watermark): 低水位, 代表 AR(分區中的所有副本)集合中最小的 logStartOffset 值
注意: LogStartOffset不可以縮寫為LSO,因為在Kafka中,LSO特指LogStableOffset
5.故障處理細節
1.follower故障
follower發生故障后會被臨時踢出ISR,待該follower恢復后,follower會讀取本地磁盤記錄的上次的HW,並將log文件高於HW的部分截取掉,從HW開始向leader進行同步。等該follower的LEO大於等於該Partition的HW,即follower追上leader之后,就可以重新加入ISR了。
2.leader故障
leader發生故障之后,會從ISR中選出一個新的leader,之后,為保證多個副本之間的數據一致性,其余的follower會先將各自的log文件高於HW的部分截掉,然后從新的leader同步數據。
注意:這只能保證副本之間的數據一致性,並不能保證數據不丟失或者不重復。
6.ISR 集合和 HW、LEO的關系
下面具體分析一下 ISR 集合和 HW、LEO的關系。
假設某分區的 ISR 集合中有 3 個副本,即一個 leader 副本和 2 個 follower 副本,此時分區的 LEO 和 HW 都分別為 3 。消息3和消息4從生產者出發之后先被存入leader副本。
在消息被寫入leader副本之后,follower副本會發送拉取請求來拉取消息3和消息4進行消息同步。
在同步過程中不同的副本同步的效率不盡相同,在某一時刻follower1完全跟上了leader副本而follower2只同步了消息3,如此leader副本的LEO為5,follower1的LEO為5,follower2的LEO 為4,那么當前分區的HW取最小值4,此時消費者可以消費到offset0至3之間的消息。
當所有副本都成功寫入消息3和消息4之后,整個分區的HW和LEO都變為5,因此消費者可以消費到offset為4的消息了
由此可見kafka的復制機制既不是完全的同步復制,也不是單純的異步復制。事實上,同步復制要求所有能工作的follower副本都復制完,這條消息才會被確認已成功提交,這種復制方式極大的影響了性能。而在異步復制的方式下,follower副本異步的從leader副本中復制數據,數據只要被leader副本寫入就會被認為已經成功提交。在這種情況下,如果follower副本都還沒有復制完而落后於leader副本,然后leader副本宕機,則會造成數據丟失。kafka使用這種ISR的方式有效的權衡了數據可靠性和性能之間的關系。