一、现象

一直在消费消息:

2024-02-19T11:06:18.132199537Z 2024-02-19 19:06:18 [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] DEBUG[org.apache.ibatis.logging.jdbc.BaseJdbcLogger

二、原因分析

1.查看配置:

enable-auto-commit: true 

auto-commit-interval-ms: 5000

相当于offset每5秒自动提交一次

与每一秒消费消息不一致,通过查资料。可以通过手动提交offset.

配置需要修改为enable-auto-commit 为false,然后设置ack模式,从而进行手动提交维护offset。

模式分好7种:

RECORD: 每处理完一条记录后提交。
BATCH(默认): 每次poll一批数据后提交一次,频率取决于每次poll的调用频率。
TIME: 每次间隔ackTime的时间提交。
COUNT: 处理完poll的一批数据后并且距离上次提交处理的记录数超过了设置的ackCount就提交。
COUNT_TIME: TIME和COUNT中任意一条满足即提交。
MANUAL: 手动调用Acknowledgment.acknowledge()后,并且处理完poll的这批数据后提交。
MANUAL_IMMEDIATE: 手动调用Acknowledgment.acknowledge()后立即提交。

一般选择手动提交,MANUAL。则需要对监听消息的方法中,引入 Acknowledgment 对象参数,并调用 acknowledge() 方法进行手动提交。

改动代码较大,于是放弃了该种方案。

2.分析日志发现某一条消息,确实再重复消费。然后看到该消息包含数组内容由上千条。然后根据代码内容分析,发现都是循环掉的,而且业务复杂,不好拆解。

所以 只能修改设置:

fetch-max-wait-ms: 2000 

当没有足够的数据(数据的大小不小于 fetch.min.bytes)返回给客户端时,服务器最大阻塞时间。

heartbeat-interval-ms: 40000

消费者协调员之间心跳的预期时间(单位是毫秒)

session-timeout-ms: 120000

会话连接超时时间,一般为心跳时间的3倍。

max-poll-interval-ms: 120000

每隔多长时间去拉取消息。合理设置预期值,尽量但间隔时间消费者处理完业务逻辑,否则就会被coordinator判定为死亡,踢出Consumer Group,进行Rebalance

max-poll-interval-records: 5

一次从拉取出来的数据条数。根据消费业务处理耗费时长合理设置,如果每次max.poll.interval.ms 设置的时间较短,可以max.poll.records设置小点儿,少拉取些,这样不会超时。

总之,尽可能在max.poll.interval.ms时间间隔内处理完max.poll.records条消息,让Coordinator认为消费Consumer还活着

三、解决方案

根据原因分析,采用了修改配置的方案:

session-timeout-ms: 120000

fetch-max-wait-ms: 2000 

heartbeat-interval-ms: 40000

max-poll-interval-records: 5

问题最终得到解决