Kafka-偏移量

偏移量提交帶來的再平衡問題

消費者提交偏移量的主要是消費者往一個名為_consumer_offset的特殊主題發送消息,消息中包含每個分區的偏移量。 如果消費者一直運行,偏移量的提交并不會產生任何影響。但是如果有消費者發生崩潰,或者有新的消費者加入消費者群組的時候,會觸發 Kafka 的再均衡。這使得 Kafka 完成再均衡之后,每個消費者可能被會分到新分區中。

為了能夠繼續之前的工作,消費者就需要讀取每一個分區的最后一次提交的偏移量,然后從偏移量指定的地方繼續處理。

但是這樣可能會出現如下的問題。

提交偏移量小于客戶端處理的偏移量

如果提交的偏移量小于客戶端處理的最后一個消息的偏移量,那么處于兩個偏移量之間的消息就會被重復處理。

提交偏移量大于客戶端處理的偏移量

如果提交的偏移量大于客戶端處理的最后一個消息的偏移量,那么處于兩個偏移量之間的消息將會丟失。 因此,如果處理偏移量,會對客戶端處理數據產生影響。

KafkaConsumer API 提供了很多種方式來提交偏移量。


自動提交

自動提交是 Kafka 處理偏移量最簡單的方式。

當 enable.auto.commit 屬性被設為 true,那么每過 5s,消費者會自動把從 poll()方法接收到的最大偏移量提交上去。

這是因為提交時間間隔由 auto.commit.interval.ms 控制,默認值是 5s。與消費者里的其他東西一樣,自動提交也是在輪詢里進行的。

消費者每次在進行輪詢時會檢查是否該提交偏移量了,如果是,那么就會提交從上一次輪詢返回的偏移量。

但是使用這種方式,容易出現提交的偏移量小于客戶端處理的最后一個消息的偏移量這種情況的問題。

假設我們仍然使用默認的 5s 提交時間間隔,在最近一次提交之后的 3s 發生了再均衡,再均衡之后,消費者從最后一次提交的偏移量位置開始讀取消息。這個時候偏移量已經落后了 3s(因為沒有達到5s的時限,并沒有提交偏移量),所以在這 3s 的數據將會被重復處理。

雖然可以通過修改提交時間間隔來更頻繁地提交偏移量,減小可能出現重復消息的時間窗的時間跨度,不過這種情況是無法完全避免的。

在使用自動提交時,每次調用輪詢方法都會把上一次調用返回的偏移量提交上去,它并不知道具體哪些消息已經被處理了,所以在再次調用之前最好確保所有當前調用返回的消息都已經處理完畢(在調用 close() 方法之前也會進行自動提交)。一般情況下不會有什么問題,不過在處理異常或提前退出輪詢時要格外小心。


手動提交

大部分開發者通過控制偏移量提交時間來消除丟失消息的可能性,并在發生再均衡時減少重復消息的數量。消費者 API 提供了另一種提交偏移量的方式,開發者可以在必要的時候提交當前偏移量,而不是基于時間間隔。 這是我們需要把把 auto.commit.offset 設為 false,讓應用程序決定何時提交偏移量。

同步提交

使用 commitSync() 提交偏移量最簡單也最可靠。這個 API 會提交由 poll() 方法返回的最新偏移量,提交成功后馬上返回,如果提交失敗就拋出異常。

代碼示例如下:

commitSync() 將會提交由 poll() 返回的最新偏移量,所以在處理完所有記錄后要確保調用了 commitSync(),否則還是會有丟失消息的風險。

如果發生了再均衡,從最近一批消息到發生再均衡之間的所有消息都將被重復處理。

同時在這個程序中,只要沒有發生不可恢復的錯誤,commitSync() 方法會一直嘗試直至提交成功。如果提交失敗,我們也只能把異常記錄到錯誤日志里。

異步提交

同步提交有一個不足之處,在 broker 對提交請求作出回應之前,應用程序會一直阻塞,這樣會限制應用程序的吞吐量。我們可以通過降低提交頻率來提升吞吐量,但如果發生了再均衡,會增加重復消息的數量。 這個時候可以使用異步提交 API。我們只管發送提交請求,無需等待 broker 的響應。

在成功提交或碰到無法恢復的錯誤之前,commitSync() 會一直重試,但是 commitAsync() 不會,這也是 commitAsync() 不好的一個地方。 它之所以不進行重試,是因為在它收到服務器響應的時候,可能有一個更大的偏移量已經提交成功。假設我們發出一個請求用于提交偏移量 2000,這個時候發生了短暫的通信問題,服務器收不到請求,自然也不會作出任何響應。與此同時,我們處理了另外一批消息,并成功提交了偏移量 3000。如果 commitAsync() 重新嘗試提交偏移量 2000,它有可能在偏移量 3000 之后提交成功。這個時候如果發生再均衡,就會出現重復消息。 commitAsync() 也支持回調,在 broker 作出響應時會執行回調。回調經常被用于記錄提交錯誤或生成度量指標。如果要用它來進行重試,則一定要注意提交的順序。

同步和異步混合提交

一般情況下,針對偶爾出現的提交失敗,不進行重試不會有太大問題,因為如果提交失敗是因為臨時問題導致的,那么后續的提交總會有成功的。 但如果這是發生在關閉消費者或再均衡前的最后一次提交,就要確保能夠提交成功。因此在這種情況下,我們應該考慮使用混合提交的方法:

在程序正常運行過程中,我們使用 commitAsync 方法來進行提交,這樣的運行速度更快,而且就算當前提交失敗,下次提交成功也可以。 如果直接關閉消費者,就沒有所謂的“下一次提交”了,因為不會再調用poll()方法。使用 commitSync() 方法會一直重試,直到提交成功或發生無法恢復的錯誤。

提交特定的偏移量

如果 poll() 方法返回一大批數據,為了避免因再均衡引起的重復處理整批消息,想要在批次中間提交偏移量該怎么辦?這種情況無法通過調用 commitSync() 或 commitAsync() 來實現,因為它們只會提交最后一個偏移量,而此時該批次里的消息還沒有處理完。 這時候需要使用一下的兩個方法:

消費者 API 允許在調用 commitSync() 和 commitAsync() 方法時傳進去希望提交的分區和偏移量的 map。 假設處理了半個批次的消息,最后一個來自主題“customers”分區 3 的消息的偏移量是 5000,你可以調用 commitSync() 方法來提交它。不過,因為消費者可能不只讀取一個分區,你需要跟蹤所有分區的偏移量,所以在這個層面上控制偏移量的提交會讓代碼變復雜。 代碼如下:

這里調用的是 commitAsync(),不過調用commitSync()也是完全可以的。在提交特定偏移量時,仍然要處理可能發生的錯誤。


監聽再均衡

如果 Kafka 觸發了再均衡,我們需要在消費者失去對一個分區的所有權之前提交最后一個已處理記錄的偏移量。如果消費者準備了一個緩沖區用于處理偶發的事件,那么在失去分區所有權之前,需要處理在緩沖區累積下來的記錄。可能還需要關閉文件句柄、數據庫連接等。 在為消費者分配新分區或移除舊分區時,可以通過消費者 API 執行一些應用程序代碼,在調用 subscribe() 方法時傳進去一個 ConsumerRebalanceListener 實例就可以了。ConsumerRebalanceListener 有兩個需要實現的方法。 public void onPartitionsRevoked(Collection partitions) 方法會在再均衡開始之前和消費者停止讀取消息之后被調用。如果在這里提交偏移量,下一個接管分區的消費者就知道該從哪里開始讀取了。 public void onPartitionsAssigned(Collection partitions) 方法會在重新分配分區之后和消費者開始讀取消息之前被調用。 下面的例子將演示如何在失去分區所有權之前通過 onPartitionsRevoked() 方法來提交偏移量。

如果發生再均衡,我們要在即將失去分區所有權時提交偏移量。要注意,提交的是最近處理過的偏移量,而不是批次中還在處理的最后一個偏移量。因為分區有可能在我們還在處理消息的時候被撤回。我們要提交所有分區的偏移量,而不只是那些即將失去所有權的分區的偏移量——因為提交的偏移量是已經處理過的,所以不會有什么問題。調用 commitSync() 方法,確保在再均衡發生之前提交偏移量。

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

推薦閱讀更多精彩內容