已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
我们订单履约链路:Kafka 3.5(KRaft,3 broker),topic order-fulfill 16 分区,生产端 outbox 表 + 定时补偿,消费端按社区主流做法走 at-least-once + 幂等表去重(这个选型社区已经讨论得比较透了,我默认它成立,下面问的是它往下再挖一层的卡点)。
消费端处理一条消息要做两件事:
问题出在:幂等表的写入,和这两步副作用,不在同一个事务里,怎么排顺序都有坑。
processed。Kafka 重试这条消息 → 幂等表命中 → 直接 ack 跳过。结果:物流其实没下单成功,系统却认为已处理 = 漏操作。 我们上个月就踩过一次,月底对账才发现 17 单物流缺失。本质是:「幂等表写入」和「非幂等副作用」这两步,既不是原子的,也缺少一个权威的『到底处理成功没有』的状态位——at-least-once 把「不丢」交给了 broker,但「不重」和「副作用到底做没做成」这两件事,幂等表一个 0/1 字段根本扛不住。
PENDING → SUCCESS / FAILED,意图是「重试时根据状态判断要不要再调 API」。卡在一个细节:PENDING 怎么区分『正在处理中』和『处理中断(崩溃/超时)』? 后者重试时要继续调 API,前者重试时不能调(避免重复)。光看状态区分不出来,只能加 started_at + 超时判断,又引入「超时阈值到底定多少、依据什么定」的新问题。想听线上真跑过、带数据的方案,而不是「理论上应该怎么做」:
PENDING 的中断恢复怎么判断(超时阈值定多少、依据什么定、怎么避免误判正在处理的请求为中断)?我自己目前倾向于「状态机 + started_at 超时 + 副作用做成先查后做」的组合,但不确定超时阈值在外部 API P99=8s 的场景下怎么定才既不漏又不重,想看看大家是怎么把这个边界画清楚的。欢迎拍砖。