支付时转圈,手一抖又点了一次,钱通常只会扣一次。靠的是幂等(idempotency):同一件事做一次和做很多次,结果一样。它像餐厅的取餐号:同一张号只能领一次餐,再来只会告诉你「已领取」。下面分 6 步讲清楚。
6 步看懂幂等
1. 手一抖#▶ 从这里看
- 重复点击、重复请求在真实世界里随时会发生,系统要假设它一定会发生。
2. 为什么会重复#▶ 从这里看
- 用户多点、页面刷新、网络超时后客户端自动重试,都会让同一个请求到达后台不止一次。
- 超时不等于失败:请求可能已经办成了,只是回音没传回来。所以盲目重发很危险。1
3. 取餐号#▶ 从这里看
4. 唯一 ID#▶ 从这里看
- 客户端为每笔操作生成一个唯一 ID(常叫幂等键,Idempotency Key),随请求一起发。关键是:重试、连点时要复用同一个 ID;每发一次就换个新 ID,后台只会当成两笔。别的操作也不能借用这个 ID。41
- 后台先把这个 ID 登记上(例如靠数据库唯一约束「抢占」),登记成功才执行并记下结果;已经登记过就不再执行:上一次已经办完,就返回保存的结果;还在办,就提示稍后再试(Stripe 对并发的同 key 请求返回 409)。不能简单「先查一下、没有再办」:两个相同请求同时到达时,可能都查到「没办过」,结果扣两次。1
5. 重试和幂等#▶ 从这里看
- 有了幂等,客户端才能放心重试,不怕重复扣钱。5
- 按钮点完变灰属于防重复提交,只能挡住手抖,挡不住网络重发和刷新;真正兜底靠后台幂等。
6. 回顾#▶ 从这里看
- 消息队列:让订单排好队、不容易丢。
- 限流:守住门口,分批放人。
- 幂等:同一笔钱只扣一次。
- 三招合起来,就是「扛住高峰」。
深入一问
唯一 ID 要记多久?
记一段够用的时间就行,比如覆盖客户端可能重试的那段时间。时间太短,迟到的重试会被当成新请求;时间太长,存储会越积越多。
消息队列为什么也需要幂等?
很多队列为了不丢消息,宁可「至少送达一次」,同一条消息偶尔会被消费两次。所以消费者处理订单时,也要靠订单号做幂等。
易错点
- ❌ 「按钮变灰就不会重复了」→ ✅ 网络重发、刷新页面都能绕过按钮,后台必须自己认出重复。
- ❌ 「超时就是失败,重发就好」→ ✅ 超时可能已经成功了,没有幂等的重发会办两次。
- ❌ 「幂等就是只能调用一次」→ ✅ 可以调用很多次,只是结果和调用一次一样。
参考资料
Footnotes
-
Stripe API 文档,《Idempotent requests》(行业通用做法示例,页面未显示日期,访问于 2026-10-14;文中写明会检测同一个 key 的并发请求)。https://docs.stripe.com/api/idempotent_requests ↩ ↩2 ↩3
-
MDN Web Docs,《Idempotent》术语表(现行文档,访问于 2026-10-13)。https://developer.mozilla.org/en-US/docs/Glossary/Idempotent ↩
-
IETF RFC 9110《HTTP Semantics》第 9.2.2 节 Idempotent Methods,2022-06 发布。https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 ↩
-
AWS 文档,《Ensuring idempotency in Amazon EC2 API requests》(重试用同一个 client token 不会重复执行;不同请求不要复用同一个 token;页面未显示日期,访问于 2026-10-14)。https://docs.aws.amazon.com/ec2/latest/devguide/ec2-api-idempotency.html ↩
-
AWS Builders’ Library,《Making retries safe with idempotent APIs》(现行文章,访问于 2026-10-13)。https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/ ↩
幕后
这部片子完全由代码生成。
系列 · 扛住高峰第 4/7 期