已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
Kafka 3.5.1(KRaft,3 broker),Java 17 + Spring Kafka 3.1,消费组 8 实例跑在 K8s 1.29 上,topic 32 分区,峰值 1.2 万 msg/s。分配器 CooperativeStickyAssignor,enable.auto.commit=false,max.poll.records=500,session.timeout.ms=45000,heartbeat.interval.ms=15000,max.poll.interval.ms=300000。消费逻辑:逐条写 MySQL 幂等表 + 业务表,批处理完再 commit。
每周 1~2 次出现「整组 rebalance 风暴」:broker 日志里 MemberId xxx generation NN has expired 连续出现 3~5 个不同 member,rebalance 一轮 40~60s,期间消费延迟从 2s 飙到 3min,幂等表命中重复消费 2~5 万条。诡异的是——
onPartitionsRevoked 的打点时间戳到回调出口之间差了 28~41s,中间只有 commitSync 的 broker 往返;__consumer_offsets 的 leader 所在节点有一次 8s 的磁盘 IO 抖动(iostat await 从 2ms 到 120ms);session.timeout 内没能正常维持 membership,最终被 coordinator 踢出,新成员加入触发整组再分配,循环 2~3 轮才稳定。onPartitionsRevoked 里的 commitSync 改成异步 commitAsync:问题依旧,且丢了一次 offset(异步回调没回来 revoke 就返回了),放弃;session.timeout.ms 到 90s:rebalance 风暴没消失,只是单轮窗口更长,重复消费更多;thread 命令抓现场:主线程栈停在 NetworkClient.awaitResponse → commitSync,确认卡的是 commit 的 broker 往返而不是业务代码;__consumer_offsets partition 的 log latency 指标、broker metrics 的 RequestQueueTimeMs)?给可复现的查询命令;commitSync 加超时在线上有几种落地姿势(RequestTimeoutMs 调小?回调里包 Future.get(timeout)?把 commit 挪到独立线程池并在 onPartitionsRevoked 里只等固定上限就放行)?各自的丢/重代价是什么,什么场景下哪种更优;session.timeout、broker P99 延迟之间有没有可推导的关系,而不是拍脑袋。我倾向最后走「有上限的等待 + 放行」,但需要有人验证过这个姿势不会引入新的 offset 回退风险(LSO 被旧 commit 覆盖)才敢上线。