已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
背景
我带团队做支付结算链路,Kafka 3.5(KRaft,3 broker),结算 topic 12 分区、消费组 6 实例,isolation.level=read_committed,offset 走事务提交(Spring Kafka 事务监听器 + 同一 transactional.id 提交消费位点)。
消费逻辑里有一步要调外部银行清算 API,单条 P99 约 90s(正常 40s)。当前配置:max.poll.records=500、max.poll.interval.ms=300000(5min)、session.timeout.ms=45000、heartbeat.interval.ms=15000。
现象
一次批处理里只要混进 1–2 条 90s 的慢记录,整批 500 条串行处理就轻松超过 5min 的 max.poll.interval.ms,实例被 coordinator 判定失联踢出组 → 触发 rebalance。
而我们是 exactly-once(read_committed + 事务位点),被踢的瞬间 in-flight 事务被 abort,已调过银行 API 的那些记录在下次 rebalance 后被重新消费 → 银行侧重复清算。一周内重复清算 3 次,都是这个路径。
已尝试的排查与结果
max.poll.interval.ms 调到 1800000(30min):确实不再被踢,但代价是——某个实例真挂了(OOM/节点宕机),要等 30min 才触发 rebalance,期间 2 个分区停摆;和 session.timeout.ms/心跳的语义也对不上,感觉把「处理慢」和「进程死」两件事混在一个超时里了。max.poll.records 降到 50:吞吐直接掉到约 1/10,而且慢记录是「按条」出现的,批次小照样会撞墙,治标不治本。期望得到的答案形态 想请有同样 exactly-once 消费 + 慢外部调用场景的同学,给一套可落地的配置 + 架构组合,最好带具体数字和判断依据,而不是「调大超时」这种一句话:
max.poll.interval.ms、session.timeout.ms、heartbeat.interval.ms 三者到底该怎么分?「处理慢」和「进程死」在 Kafka 里是不是本就该用两个不同的机制(poll 间隔 vs 会话超时)去区分?如果该分开,推荐的取值区间是多少、为什么?max.poll.interval.ms 永远不会被突破?具体怎么算这个上界?先谢过大家,我这边可以把 6 实例的 lag 曲线和 rebalance 日志贴出来配合排查。