手一抖点了两次支付,为什么只扣一次钱?

发布 · 视频 2:10 · 约 3 分钟读完 · #后端#幂等#高并发

章节

  1. 0:00手一抖
  2. 0:18为什么会重复
  3. 0:40取餐号
  4. 1:02唯一 ID
  5. 1:24重试和幂等
  6. 1:45回顾

快捷键:K/空格 播放暂停 · J/L 上/下一章 · ↑/↓ 切换章节

支付时转圈,手一抖又点了一次,钱通常只会扣一次。靠的是幂等(idempotency):同一件事做一次和做很多次,结果一样。它像餐厅的取餐号:同一张号只能领一次餐,再来只会告诉你「已领取」。下面分 6 步讲清楚。

6 步看懂幂等

1. 手一抖#▶ 从这里看

  • 重复点击、重复请求在真实世界里随时会发生,系统要假设它一定会发生。

2. 为什么会重复#▶ 从这里看

  • 用户多点、页面刷新、网络超时后客户端自动重试,都会让同一个请求到达后台不止一次。
  • 超时不等于失败:请求可能已经办成了,只是回音没传回来。所以盲目重发很危险。1

3. 取餐号#▶ 从这里看

  • 幂等:同一个操作执行一次和执行多次,产生的效果一样。2
  • 在 HTTP 里,GET、PUT、DELETE 按规范应该是幂等的,POST 通常不是,所以「下单」「支付」这类 POST 请求要额外处理。3

4. 唯一 ID#▶ 从这里看

  • 客户端为每笔操作生成一个唯一 ID(常叫幂等键,Idempotency Key),随请求一起发。关键是:重试、连点时要复用同一个 ID;每发一次就换个新 ID,后台只会当成两笔。别的操作也不能借用这个 ID。41
  • 后台先把这个 ID 登记上(例如靠数据库唯一约束「抢占」),登记成功才执行并记下结果;已经登记过就不再执行:上一次已经办完,就返回保存的结果;还在办,就提示稍后再试(Stripe 对并发的同 key 请求返回 409)。不能简单「先查一下、没有再办」:两个相同请求同时到达时,可能都查到「没办过」,结果扣两次。1

5. 重试和幂等#▶ 从这里看

  • 有了幂等,客户端才能放心重试,不怕重复扣钱。5
  • 按钮点完变灰属于防重复提交,只能挡住手抖,挡不住网络重发和刷新;真正兜底靠后台幂等。

6. 回顾#▶ 从这里看

  • 消息队列:让订单排好队、不容易丢。
  • 限流:守住门口,分批放人。
  • 幂等:同一笔钱只扣一次。
  • 三招合起来,就是「扛住高峰」。

深入一问

唯一 ID 要记多久?
记一段够用的时间就行,比如覆盖客户端可能重试的那段时间。时间太短,迟到的重试会被当成新请求;时间太长,存储会越积越多。

消息队列为什么也需要幂等?
很多队列为了不丢消息,宁可「至少送达一次」,同一条消息偶尔会被消费两次。所以消费者处理订单时,也要靠订单号做幂等。

易错点

  • ❌ 「按钮变灰就不会重复了」→ ✅ 网络重发、刷新页面都能绕过按钮,后台必须自己认出重复。
  • ❌ 「超时就是失败,重发就好」→ ✅ 超时可能已经成功了,没有幂等的重发会办两次。
  • ❌ 「幂等就是只能调用一次」→ ✅ 可以调用很多次,只是结果和调用一次一样。

参考资料

Footnotes

  1. Stripe API 文档,《Idempotent requests》(行业通用做法示例,页面未显示日期,访问于 2026-10-14;文中写明会检测同一个 key 的并发请求)。https://docs.stripe.com/api/idempotent_requests ↩ ↩2 ↩3

  2. MDN Web Docs,《Idempotent》术语表(现行文档,访问于 2026-10-13)。https://developer.mozilla.org/en-US/docs/Glossary/Idempotent ↩

  3. IETF RFC 9110《HTTP Semantics》第 9.2.2 节 Idempotent Methods,2022-06 发布。https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 ↩

  4. 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 ↩

  5. AWS Builders’ Library,《Making retries safe with idempotent APIs》(现行文章,访问于 2026-10-13)。https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/ ↩

幕后

这部片子完全由代码生成。