Spring Boot Kafka配置MANUAL_IMMEDIATE仍出现消息重复消费问题
核心原因及对应解决办法
优雅停机未开启,偏移量提交请求未完成就销毁消费者
Spring Boot默认未开启优雅停机,部署时收到终止信号会直接销毁容器。即使代码已经调用acknowledge()方法,若此时提交偏移量的网络请求尚未被Kafka Broker确认,消费者进程就被终止,Broker端不会保存最新偏移量。重平衡后新分配分区的消费者会拉取旧偏移量的消息,导致重复消费。
解决配置:# application.properties 配置 server.shutdown=graceful spring.lifecycle.timeout-per-shutdown-phase=30s同时调整Kafka监听器容器停机超时,预留偏移量提交时间:
factory.getContainerProperties().setStopTimeout(30000);默认异步提交无校验,提交失败无感知
MANUAL_IMMEDIATE模式下,Spring Kafka默认采用异步提交偏移量,acknowledge()方法仅将提交请求放入队列就立刻返回,日志打印MessagingConsumer acknowledge:仅代表方法调用成功,不代表Broker已经确认偏移量提交成功,提交过程中出现网络波动、Broker繁忙等问题都会导致提交失败无感知。
解决办法:开启同步提交,确保提交成功才继续执行后续逻辑:// 容器配置中添加 factory.getContainerProperties().setSyncCommits(true); factory.getContainerProperties().setCommitTimeout(5000);若需保留异步提交能力,可自定义
AcknowledgmentCallback添加提交结果回调,捕获提交失败异常做兜底处理。消费者超时配置不合理,重平衡触发过早
你当前仅配置了SESSION_TIMEOUT_MS_CONFIG,未配置心跳间隔,若session超时时间设置过短(小于10秒),部署过程中实例短暂无法发送心跳就会被组协调器判定为下线,触发重平衡时偏移量还未完成同步,新消费者拉取到旧偏移量的消息。另外CooperativeStickyAssignor渐进式重平衡需要一定同步时间,滚动部署速度过快也会导致偏移量同步不及时。
解决配置:// 消费者配置新增/调整 props.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, 3000); // session超时至少为心跳间隔的3倍,给部署预留缓冲时间 props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, 15000);部署时采用单实例滚动发布,每次下线实例后等待30秒确认重平衡完成、偏移量同步后再操作下一个实例。
额外优化建议:你当前代码逻辑为先提交偏移量再处理业务,若业务处理过程中出现异常,消息会直接丢失无法重试。建议调整逻辑为先完成业务处理,再调用
acknowledge()提交偏移量。
内容的提问来源于stack exchange,提问作者user3611168

