一.產生的問題
在.NET環境下使用kafka,消費者長時間消費,會報“ Application maximum poll interval ”錯誤。
二.重現問題
2.1.消費者配置
SessionTimeoutMs(會話超時時間)和MaxPollIntervalMs(上一次拉取消息和本次拉取消息之間的時間間隔)配置爲10秒。
1 var config = new ConsumerConfig 2 { 3 BootstrapServers = brokerServer, 4 //同組輪詢,不同組廣播 5 GroupId = groupName, 6 7 EnableAutoCommit = false, 8 9 AutoOffsetReset = AutoOffsetReset.Earliest, 10 11 EnablePartitionEof = true, 12 PartitionAssignmentStrategy = PartitionAssignmentStrategy.Range, 13 14 //心跳(<)超時 15 SessionTimeoutMs = 10000, 16 //上一次拉取消息和本次拉取消息之間的時間間隔 17 MaxPollIntervalMs = 10000, 18 };
2.2.模擬一個耗時的業務
DoBussinessForLongTime()方法中特意休眠12秒,模擬做業務慢場景。
1 ConsumeResult<Ignore, string> consumeResult = null; 2 3 while (true) 4 { 5 try 6 { 7 //拉取kafka消息 8 consumeResult = consumer.Consume(cancellationToken); 9 #region 模擬長時間做公司業務 10 { 11 DoBussinessForLongTime(consumeResult); 12 } 13 #endregion 14 15 consumer.Commit(consumeResult); 16 } 17 catch (ConsumeException e) 18 { 19 Console.WriteLine($"Consume error: {e.Error.Reason}"); 20 } 21 catch (KafkaException e) 22 { 23 Console.WriteLine($"Commit error: {e.Error.Reason}"); 24 } 25 catch (OperationCanceledException e) 26 { 27 throw e; 28 } 29 catch (Exception e) 30 { 31 Console.WriteLine($"Commit error: {e}"); 32 } 33 } 34 35 36 /// <summary> 37 /// 長時間做公司業務 38 /// 配合SessionTimeoutMs = 10000,MaxPollIntervalMs = 10000使用 39 /// </summary> 40 /// <param name="consumeResult"></param> 41 private static void DoBussinessForLongTime(ConsumeResult<Ignore, string> consumeResult) 42 { 43 Console.WriteLine($"DoBussinessForLongTime Start {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); 44 Thread.Sleep(12000); 45 Console.WriteLine($"DoBussinessForLongTime End {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); 46 }
給名爲MyTopic的主題生產3條消息,分別爲a、b、c。
我們最終看到在拉取第2條消息時,報ConsumeException異常了,紅色框內的異常是我們主動打印出來的,黃色框內的異常是.NET自己打印出來的。我們來翻譯下這句話“ Application maximum poll interval (10000ms) exceeded by 183ms (adjust max.poll.interval.ms for long-running message processing): leaving group”,這句話的意思是說:拉取最大時間間隔爲10秒,超過了183毫秒,離開組。
詳細解釋下這個報錯是什麼意思:這個報錯是指你上一次拉取消息和本次拉取消息之間的時間間隔超過了kafka允許的最大的拉取消息的時間間隔(kafka裏默認配置是5分鐘,我們修改了消費者配置是10秒),也就是說kafka認爲你拉取消息後做了大於10秒的業務,拉到消息是要去做業務的(每家公司做的業務不同),什麼業務能做10秒呢?(做完業務纔再去拉取下一條消息),所以kafka的組協調器(GroupCoordinator)就認爲你這個消費者(每一個消費者都歸屬於一個消費者組)不給力,覺的你幹活太慢了,做業務太慢了,把你這個消費者從消費者組移除出去,就報錯了。
這個問題產生的原因:是咱們引入的第三方的dll(.NET裏引用的是Confluent.Kafka.dll)在長時間消費過程中,會偶發判斷上一次拉取消息和本次拉取消息之間的時間間隔有誤(懷疑),明明沒有超過5分鐘(kafka裏默認配置是5分鐘),但是卻判斷是超過了5分鐘。
三.如何解決這個問題?
使用異常過濾器,捕獲到“Application maximum poll interval”異常,記錄下日誌就好了,然後繼續去拉取本次失敗的消息(前提是已經對之前拉取到的消息做了偏移量提交)。
1 catch (ConsumeException e) when (e.Error.Reason.Contains("Application maximum poll interval"))//滿足條件才進入catch 2 { 3 //此處記錄下日誌
4 }