开放问答
Kafka 开幂等 + max.in.flight=5 后 MySQL 流水表偶发重复,如何定位 broker 幂等去重失效
该问题的正文、回答与评论。
提问者 江若衡-155 · 状态 open
Kafka生产者幂等leader切换max.in.flight消息可靠性
【背景】
Kafka 3.5(3 broker,rack 分布,ISR=2),topic order-flow 32 分区,producer 8 实例(Spring Kafka 3.1,每实例一个 producer 对象),日均约 1800 万条。consumer 4 实例消费后写 MySQL 8.0 流水表(uk_biz_id 唯一键),走"先 SELECT 后 INSERT + 唯一键兜底"的幂等。producer 端配置:enable.idempotence=true、acks=all、max.in.flight.requests.per.connection=5、batch.size=256k、linger.ms=10。
【现象】
近三周 MySQL 流水表累计出现 7 次 uk_biz_id 冲突(即同一 biz_id 被写入两次),冲突的 7 条记录在 Kafka 侧 broker 日志里看不到重复的 batch(用 kafka-console-producer 回查 + __consumer_offsets 对比,offset 上没有重复)。也就是说重复不是 producer 重发,更像是 broker 在 leader 切换 / 重试路径下幂等去重窗口没兜住,或者 consumer 侧 fetch 重复。7 次里 5 次恰好发生在 broker-2 做 leader 切换的窗口内(kafka.server 日志能看到 Epoch: 3 变化),另外 2 次无明确切换。
【已尝试的排查与结果】
- 把
max.in.flight.requests.per.connection从 5 降到 1:跑了一周,冲突 0 次——但这只是规避,没定位到根因,且吞吐掉了约 18%,不能长期这么跑; - 在 broker 侧加
log.producer.expire.ms监控(默认 10min),怀疑是 producerId 元数据在 10min 空闲后被清理,重试时 broker 当成新 producer 写入——但 producer 端 8 实例都是常驻的,空闲超过 10min 的概率不高,且冲突时间点 producer 都在持续发送; - consumer 侧把
max.poll.records从 500 降到 100、session.timeout.ms从 45s 调到 30s:无效,冲突仍在切换窗口出现。
【期望得到的答案形态】 希望社区给一个可复现的排查路径,最好包含:
- broker 端幂等去重(producerId + epoch + batch sequence)具体在
Log.produce()哪一步生效,以及 leader 切换时__transaction_log/producerId元数据的迁移顺序,指出哪一步在 3.5 有已知 bug(如果有); - 一个具体的复现步骤(比如
kafka.tools脚本 + 切换时机),让我能在测试环境稳定复现; - 确认
max.in.flight=5在幂等开启下是否真的安全(broker 端 sequence 去重),还是仍然有窗口; - 如果最终定位到是 consumer fetch 重复(而非 producer 重复),给出区分两者的 broker / consumer 日志关键字。
评论
暂无评论。