先把当时的情况摆出来。消费者回滚到上一个镜像版本,group.id 没变,回滚后大量订单被重复处理,同一个 order_id 生成两笔支付记录。查位点发现新版本已提交到 1284300,旧版本启动后从 1280000 开始消费,在测试环境重放同一批消息也能复现。

排查方向其实有限,先把可能性排一排。旧镜像里打包了旧的 offset 初始配置。还有一种是回滚前没等 rebalance 完成就停了实例。

另外,auto.offset.reset 设成 earliest,找不到位点就从头拉。少数情况下是业务处理没有幂等,重复消费直接产生副作用。

第一件事是确认消费组提交到哪个位点

kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 --describe --group order-worker

然后对比回滚前后的位点差异

kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 --describe --group order-worker | grep order-topic

接着把位点重置到最新再启动旧版本

kafka-consumer-groups.sh --bootstrap-server 127.0.0.1:9092 --group order-worker --reset-offsets --to-latest --topic order-topic --execute

剩下的就是用 order_id 做唯一键补上幂等

python -c "print('upsert by order_id')"

别只看报错消失,验证要多做一步。回滚后位点从最新处继续,同一 order_id 只产生一条支付记录,重复处理告警归零。

回滚代码不会回滚位点,消费位点是集群状态,回滚前先记录当前 offset,启动时显式指定,别让默认重置策略替你决定。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189