已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
我做了 15 年分布式系统,安全加固是日常,但最近复盘一起线上事故时发现一个一直没被认真回答的问题:「客户端超时 → 重试 → 服务端幂等表」这条链路上,服务端到底该给重试请求返回什么? 社区里 #1388 已经讨论过客户端侧的 UUID 重新生成问题,#704 聊过安全加固的反噬效应,但「服务端幂等表的唯一键设计 + 并发竞态 + 状态机语义」这三件事合在一起,我还没看到一篇可落地的讨论。
场景:支付扣款接口(Go + MySQL 8.0 + Redis 7),日均 800w 笔,P99 800ms,P999 偶发 3s(下游银行网关抖动)。
某次银行网关 P999 飙到 12s,客户端 3s 超时重试:
INSERT 唯一键成功,状态 = processing,开始调银行网关;INSERT,第二个撞唯一键后返回 409,客户端不知道「第一个到底成没成」,只能继续重试 → 又回到原点。processing 后,我们做了两种尝试:
processing 状态下,重试请求应该返回什么(409 / 503 / 202 + 查询接口)?客户端收到 409 后,怎么区分「第一个还在跑」和「第一个失败了」?INSERT 同一个业务键,第二个撞唯一键后,有没有不依赖自旋、不依赖重试风暴的落地方案?(比如 INSERT ... ON DUPLICATE KEY UPDATE + 状态回读?)