最近项目上遇到一个kafka重复消费的问题,大体描述一下:
程序日志显示一直在重复消费从kafka中获取到的其中500条记录,处理这500条数据耗时8分钟。kafka的server.log日志一直在提示rebalance。
网上找了很多帖子,发现其中对于max.poll.records和session.timeout.ms两者关系的描述基本都是错误的,错误描述如下:
# max.poll.records条数据需要在session.timeout.ms这个时间内处理完,默认:500
# 即 max.poll.records * (处理能力) <= session.timeout.ms 可正常消费,不满足会出现rebalance
spring.kafka.consumer.max-poll-records=500
ok,口说无凭,实操一下:
配置如下:
spring.kafka.consumer.max-poll-records=20
spring.kafka.consumer.properties.session.timeout.ms=10000
处理程序每次用Thread.sleep(1000)来模拟,即程序的处理能力为1秒消费一条记录,安装上述配置,20条记录至少需要20秒,配置10秒显然不够,肯定会出现rebalance。
实测结果,正常处理,kafka也没有出现rebalance。
why? 显然,max.poll.records和session.timeout.ms两者的关系不是如此,继续深入一下。
我们再来看看上面的session.timeout.ms,指的是什么,为了准确,直接去官网:
翻译一下,基本就是说:
session.timeout.ms为会话的超时限制。如果consumer在这段时间内没有发送心跳信息,则它会被认为挂掉了,并且reblance将会产生,必须在[group.min.session.timeout.ms, group.max.session.timeout.ms]范围内。默认:10000。
显然并没有提到与max.poll.records的关系。
查阅官网,发现一个属性max.poll.interval.ms,官网描述如下:
基本意思就是消费者两次调用poll()取数据的最大延迟时间,超过这个时间消费组会发生rebalance。
消费者第一次poll到数据后,会开始消费,直到本次数据处理完毕,才会进行下一次poll,也就是说:
max.poll.records * (处理能力) <= max.poll.interval.ms,程序即可正常消费。
实操一下,现象确实如此,这里就不附带结果了。
写这篇帖子,主要是因为鄙人踩了这个坑,希望其它人不要继续了,哈哈。
从上面公式可以看到,我们只要保证程序处理能力稳定,不会随着时间或者数据量增大,那这rebalacnce就不会出现了。
可以采用异步消费的方式。