记一次线上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)
先处理再提交位移,当某一条处理超时导致提交失败,后面扔可正常消费两分区,且提交失败的消息会被重复消费
在这里插入图片描述

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