Appearance
幂等 API:让超时后的重试保持安全
修订于 2026-10-12:原文的支付平台事故和“生产验证”说法没有材料,已删除。示例是接口设计方法,不是本站事故记录。
客户端发出写入请求后超时,无法仅凭超时判断服务端是否执行了操作。若再次发送相同请求,可能重复创建资源或重复触发副作用。幂等接口的目标是让同一个业务意图在重试中不会产生多次副作用。
幂等键如何使用
客户端为一次业务操作生成稳定的请求标识,在所有重试中复用。服务端在确定的作用域内保存该标识、请求参数摘要、处理状态与结果。相同标识、相同参数再次到达时,服务端返回之前的结果或可查询状态;相同标识但参数不同,应明确拒绝或按接口契约处理。Amazon EC2 的 client token 就是一个有文档化作用域和参数匹配规则的例子。
幂等键不是“有 UUID 就够了”。实现还必须明确:
- 作用域:按租户、用户、资源、区域还是全局去重?
- 生命周期:键保存多久,过期后重试如何处理?
- 并发原子性:两个相同请求同时到达时,只能有一个执行副作用。
- 结果语义:首次成功、失败、执行中与结果未知分别返回什么?
- 参数绑定:同一键不能被意外复用于不同业务请求。
常见实现路径
数据库唯一约束可用于简单的“只创建一次”场景,但需要把去重记录与业务写入放在同一事务边界内。更复杂的操作可用状态机记录“处理中、成功、失败、需核对”等状态,并提供查询接口。若副作用在外部支付或消息系统中,还要对外部操作本身使用对应的幂等机制;本地去重不自动保护外部调用。
消费者处理可能重复投递的消息时,也应按业务事件 ID 去重。收到重复消息后,应确认前次处理的实际状态,而不是盲目重做。
测试清单
- 相同键、相同参数连续发送与并发发送。
- 相同键、不同参数发送。
- 服务端完成写入但响应丢失后的重试。
- 首次处理还未完成时的重复请求。
- 键过期、存储故障、跨区域请求和恢复后的重放。
- 外部副作用成功但本地状态更新失败的恢复流程。
幂等性依赖接口契约。不同云服务对作用域、有效期和返回结果有不同规定,应以所调用的 API 文档为准。