首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >幂等设计实战:重复消费、重复支付与重试风暴的统一解法

幂等设计实战:重复消费、重复支付与重试风暴的统一解法

原创
作者头像
PikeTalk
发布于 2026-10-16 07:34:51
发布于 2026-10-16 07:34:51
50
举报

分布式系统的第一课:重复一定会发生

MQ 至少一次投递、HTTP 超时重试、用户双击提交、网关层自动 failover——重复请求不是异常,是常态。幂等设计的目标只有一个:同一个业务操作执行一次和执行 N 次,结果一致。它不是某个中间件的配置,而是业务接口的属性,必须在设计期想清楚。一、幂等键:一切设计的起点

幂等的载体是「业务唯一键」,选错键一切白搭:

  1. 天然业务键:支付用「订单号+支付单号」、扣库存用「订单号+SKU」——业务上天然唯一,优先使用;
  2. 客户端生成的请求 ID:前端进入页面时生成 UUID 随请求提交(不是每次点击重新生成),服务端以此去重;
  3. 状态机版本号:工单、审批流用「单号+当前状态」做条件更新,天然防重放。

反例:用「用户 ID+时间戳」做键——时间戳每次都变,等于没有幂等。

二、三层实现强度,按业务选型

  1. 数据库唯一约束(最可靠):幂等键做唯一索引,重复插入直接报错回滚。插入型业务(订单、流水)一律用这层兜底,其他手段失效时它是最后防线;
  2. 条件更新(状态机类):UPDATE orders SET status='paid' WHERE order_id=? AND status='unpaid'——返回受影响行数为 0 即重复请求,配合唯一约束覆盖绝大多数写操作;
  3. Redis SETNX 去重(高性能前置):SET idempotent:{key} 1 NX EX 600,挡在业务逻辑前面快速失败。注意它只是优化不是保证:Redis 超时或过期后仍可能穿透,必须与第 1/2 层组合使用。

三、容易被忽略的三个细节

  1. 重复请求的响应要一致:第一次返回「下单成功」,第二次重复请求应返回相同结果(或明确的「已处理」),而不是报错——移动端常见的「看似失败实则成功」事故多源于此。把首次处理结果缓存到幂等记录里,重入时直接返回;
  2. MQ 消费的幂等粒度:消费端用「消息的业务键」而非 msgId 去重——重发场景下 msgId 会变,业务键不变;
  3. 重试风暴的联动限流:下游故障时上游重试会把流量放大数倍,幂等只能保证不出错,还要配退避(指数+jitter)与重试预算(如重试流量占比超 10% 熔断重试)。

四、验收标准

幂等做没做对,用三个用例测:同请求连发两次结果一致;MQ 消息重复投递只产生一条业务记录;网络超时后客户端重试不产生双倍扣款。这三个用例过不了,任何「我们中间件保证不重复」的说法都不可信。

幂等的本质是把「重复」从故障降级为常态输入。接口设计时先问一句:这个操作被调用两次会发生什么?——答不上来,就先把幂等键定了再写代码。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 分布式系统的第一课:重复一定会发生
  • 二、三层实现强度,按业务选型
  • 三、容易被忽略的三个细节
  • 四、验收标准
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档