对外提供支付回调和订单创建接口时,如何设计幂等,避免超时重试造成重复数据?
我会先定目标和容量,再拆核心链路:从重复请求来源、唯一键、状态机和幂等令牌设计可靠接口
我不会直接画架构图,会先确认目标、规模和一致性要求。同一个操作执行一次或执行多次,系统最终产生的业务效果相同,就称为幂等。HTTP GET、PUT、DELETE 在协议语义上通常被设计为幂等,但真实业务是否幂等仍取决于服务实现。 网络超时无法证明服务端没有执行。客户端、网关、消息队列都可能重试,因此订单创建、支付、库存扣减等关键写操作必须主动设计幂等。
容量有了以后,再把入口、核心处理和数据落点串起来。沿着「客户端生成业务请求号 → 服务端原子登记幂等键 → 执行业务状态迁移 → 保存结果快照 → 重复请求返回同一结果」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 客户端生成业务请求号 幂等键必须代表同一业务意图,随机重试每次换键会完全失去去重作用。 服务端原子登记幂等键 登记与业务写最好在同一数据库事务通过唯一约束完成,先查后写存在并发窗口。 数据库 UNIQUE(idempotencykey):并发最终裁决。 请求状态机:PROCESSING/SUCCESS/FAILEDUNKNOWN。 我会先确认请求实际走到了哪条路径,再用运行数据验证,不会只看类名或配置猜测。
关键参数要从峰值流量和资源上限反推。在登记前后、业务提交后、返回前 kill,重放同一 key 核对结果。
正常链路之外,还要设计失败补偿和可验证的恢复流程。回调按 HTTP 请求 ID 去重,但渠道每次重试都会生成新请求 ID。改用支付单号+事件类型作为业务幂等键,并以积分流水唯一约束最终裁决后才正确。 把请求 ID 当业务 ID 导致重试绕过去重:幂等命中率:业务意图生成稳定 key。 处理中超时后两个执行者并发恢复:处理中超时数:记录与业务同事务。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「幂等冲突率」为主基线,记录值应满足「记录活动/稳态基线」;同时保存 幂等命中率、处理中超时数,使后续变化能够回到同一时间轴比较。
最后再讲扩容、成本和方案边界。方案:更适合的场景:主要收益:代价与边界。 唯一约束:最终副作用在单数据库:并发裁决强、证据持久:热点索引与冲突处理。 状态表:多阶段操作和结果查询:状态可恢复、便于补偿:生命周期与清理复杂。 下游幂等令牌:跨服务最终资源:端到端保护:依赖下游契约和保留窗口。 选型至少带上 峰值流量、数据规模、依赖容量、一致性目标和故障预算,并用上面的量化基线验证;未知数据应明确为待测假设。