記一次線上Kafka CommitFailedException

CommitFailedException,顧名思義就是Consumer客戶端在提交位移時出現錯誤或異常,還是那種不可恢復的嚴重異常。
報錯:

Caused by: org.apache.kafka.clients.consumer.CommitFailedException: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing the session timeout or by reducing the maximum size of batches returned in poll() with max.poll.records.

大致意思就是,本次提交位移失敗,原因是消費者組開啓了Rebalance過程,並且將要提交位移的分區分配給了另一個消費者實例,出現這種情況的原因是,消費者實例連續兩次調用poll方法的時間間隔超過了期望的max.poll.interval.ms設置的參數值,就是說消費者實例處理消費花費時間過長,耽誤了poll的調用。並給出了兩個相應的解決辦法:
1、增加兩次poll時間間隔max.poll.interval.ms參數值
2、減少poll方法一次性返回的消息數量,即減少max.poll.records參數值

關於Rebalance:
Rebalance就是讓一個消費者組下所有的消費者就如何消費訂閱主題的分區達成共識的一個過程,所有的實例共同參與這個分區分配過程。一般Rebalance會存在以下弊端:

  • 影響Consumer的TPS,因爲在Rebalance期間,所有的Consumer都要停止手頭的事情。

  • Rebalance過程慢,效率低,一個Group下幾百個Consumer實例Rebalance一次可能按小時計算(未驗證)。這種場景下,這個Group的Consumer幾乎等於癱瘓了。

所以在生產環境中應儘量避免發生Rebalance,要避免,就得知道造成Rebalance的因素,主要有以下三點:

  • Group成員發生變化
  • 訂閱主題數量發生變化
  • 訂閱主題的分區數發生變化

從第二點和第三點可以看到修改consumer的主題數量,以及修改consumer訂閱的主題的partition數量,都會造成Rebalance,這種可儘量避免主動觸發。而第一點是最常見的,對於consumer處理時間過長造成的Rebalance就是第一種因素,因爲consumer處理時間過長,Broker認爲Consumer掛掉,引發Group組成員發生變化,繼而引發Rebalance過程。平時啓動一個配置有相同Group ID值的Consumer,Broker的Coordinator也會觸發Rebalance,重新給組分配分區,這種情況一般都是計劃內的,我們應儘量避免的是計劃外的Consumer被錯誤地認爲掛掉而被踢出Group的情況,比如Consumer處理時間過長的原因。還有Broker在session.timeour.ms期間內沒收到Consumer的心跳請求,也會被認爲掛了,觸發Rebalance。

綜上,恰當的設置參數,可降低生產環境的Rebalance次數,提高Consumer端TPS。

  • max.poll.interval.ms 設置程序兩次poll方法調用的最大時間間隔。
  • max.poll.records poll方法一次性返回的消息數量
  • session.timeout.ms consumer存活性判斷時間間隔
  • heartbeat.interval.ms consumer發送心跳請求的頻率

解決方案:
consumer處理時間過長,超過max.poll.interval.ms設定的閾值,必然會導致消費者組重平衡,消費者組重平衡之後如果能提交位移成功,便可繼續消費,如果提交位移失敗便被踢出消費者組。且消費過但位移提交失敗的數據會被重複消費。防止消息處理時間過長導致位移提交失敗異常,可從以下着手:
1、優化業務處理邏輯,縮短單條消息處理時間
2、合理設置max.poll.interval.ms時間間隔,不過Kafka 0.10.1.0之前的版本是沒有這個參數的,只能通過設置session.timeout.ms參數的值,但是session.timeout.ms還同時是consumer存活性判斷時間間隔。
3、合理設置max.poll.records,減少一次性消息消費總數。
4、採用多線程消費消息。

實驗:
只做了簡單的案例,還有多消費者實例等更多的案例沒有實驗,但可以知道的是,處理時間過長,超過設置的閾值,必然導致消費重組,且如果位移提交失敗,消息會被重複消費。

Partition:2
Consumer:1
max.poll.interval.ms=3s
max.poll.records=1
processTime=2s(偶爾5s)
先處理再提交位移,當處理超時時,consumer立馬被踢出組,不再消費數據
在這裏插入圖片描述
先提交位移再處理,當處理超時,拋出警告,繼續消費
在這裏插入圖片描述
以上是在沒有異常捕獲的情況下產生的現象,爲保證consumer一直活着,以下均在異常被捕獲的情況下測試:

Partition:2
Consumer:1
max.poll.interval.ms=10s
max.poll.records=1
處理時長=5s
先處理再提交或者先提交再處理都正常消費提交位移

Partition:2
Consumer:1
max.poll.interval.ms=3s
max.poll.records=1
處理時長=5s
先提交位移再處理 並設置啓動從最新開始消費或者從頭開始消費,都是正常消費兩分區數據並提交位移,只是報warn
在這裏插入圖片描述
Partition:2
Consumer:1
max.poll.interval.ms=3s
max.poll.records=1
處理時間=5s
先處理再提交位移並設置啓動從最新開始消費
啓動沒拿到數據便報commit failed,後面基本消費不到數據,一直報錯,偶爾能消費到數據
在這裏插入圖片描述
如果設置啓動從頭開始消費,啓動消費到數據再報commit failed,後面便一直消費同一條數據,報錯
在這裏插入圖片描述
Partition:2
Consumer:1
max.poll.interval.ms=3s
max.poll.records=1
處理時間=2s(偶爾5s)
先處理再提交位移,當某一條處理超時導致提交失敗,後面扔可正常消費兩分區,且提交失敗的消息會被重複消費
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章