很多人以为幂等性是个已解决的问题。加个Idempotency-Key,存下响应,重试时直接返回——搞定。演示环节确实能跑通。
但真正的麻烦从第二次请求开始。
![]()
客户端第一次发请求:POST /payments,带一个Key叫abc-123,内容是给acc_1账户付10欧元。服务器没见过的Key,创建支付,记录响应。一切顺利。
![]()
第二次请求来了。它可能是干净的重试——Key相同,内容相同,直接返回缓存结果。但也可能是以下任何一种情况:
请求抵达时,第一次还在处理中。你的幂等层突然变成了并发控制组件。
第一次创建了本地支付记录,却在发事件前崩溃。本地数据与外部副作用不同步。
第一次调了支付提供商,钱已经扣了,你的进程却在记录结果前死掉。数据库无法推断资金是否实际转移。
最棘手的是:Key相同,内容变了——金额从10欧改成100欧。这是重试?客户端Bug?还是全新操作?该返回旧响应、拒绝请求,还是把(Key+内容)当成新身份?
![]()
你可以选任何策略,只要文档写清楚。但服务器必须有明确立场。我的倾向是:相同作用域Key配合不同规范化命令,直接报错。这能尽早暴露客户端Bug——一个以为自己安全重试10欧支付的客户端,不该被服务器默默当成别的请求处理。
真正重要的场景,是"重放缓存"模型覆盖不了的:并发重试、部分本地成功、下游状态未知、Key相同但命令不同、没带Key的重复操作、过期后重试、部署或切流后的重试。
如果你的设计只处理"完成的相同命令重试",那它只是个重放缓存。对某些接口或许够用,但远未解决完整问题。
幂等性的本质是"效果"。一个操作幂等,是指执行一次或多次,产生的预期效果相同。这个定义里,"效果"二字承担了所有重量。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.