4. 重试可能带来的问题:幂等性与雪崩归纳总结

重试机制不是万能的。用好了,它能扛住瞬态故障;用不好,它会加倍伤害你的系统。

我在刚做接口重试时,就踩过一个大坑。当时一个支付接口超时了,我直接配置了 3 次重试。结果用户被扣了 4 次钱。嗯,那次事故让我彻底记住了两个字:幂等。另一个坑更吓人——重试风暴把下游服务打挂了,然后整个链路像多米诺骨牌一样塌掉。说白了,这就是雪崩。

这一章,我把这两个问题拆开揉碎讲清楚。你最好先背下来:不做幂等就去重试 = 制造脏数据;不做防护就去重试 = 引爆雪崩。

4.1 幂等性问题——同一个请求,不能造成多次副作用

什么是幂等?你用同一个请求调一次和调 N 次,系统状态应该保持一致。读操作天然幂等,但写操作就不一定了。尤其是支付、下单、转账这类操作。

为什么重试会破坏幂等?因为重试本质上就是把同一个请求又发了一遍。如果被调方(比如支付网关)已经成功处理了第一次请求,只是响应超时了,第二次重试就会再执行一次扣款。用户就多付了钱。

我曾经遇到过:一个订单服务在创建订单时,因为调用库存系统超时,自动重试了 3 次。结果同一个订单在数据库里插了 4 条记录。排查时发现,库存竟然扣了 4 次。最后不得不逐条手动回滚。那个周末,我泡在数据库跟前度过的。

解决幂等性问题的常见做法:

  • 全局幂等键(Idempotency Key):每个请求带上唯一 ID。服务端根据这个 ID 去重。第一次执行后把结果缓存起来,后续相同 ID 的请求直接返回缓存结果。我推荐用 UUID 或雪花 ID。
  • 去重表 + 唯一索引:在数据库里建一张去重表,把幂等键设为唯一索引。插入成功说明是第一次请求,插入失败说明已处理过。注意,去重表要单独建,别跟业务表混在一起,避免锁竞争。
  • 状态机驱动:对于订单等有明确状态流转的实体,可以用状态机确保每个状态只能向前走一次。比如“待支付→已支付→已发货”,重试时如果发现已是“已支付”,直接返回成功,不再执行扣款。

我个人习惯,在涉及钱的接口上,三者同时使用:上游传幂等键,下游用去重表兜底,业务状态机做最终防护。三重保险,基本就不会出事。

4.2 雪崩问题——重试风暴才是真正的隐形杀手

如果说幂等性是接口级别的“内伤病”,雪崩就是集群级别的“瘟疫病”。

先看一个典型场景。假设你的 A 服务依赖 B 服务。某天 B 服务响应变慢,从 50ms 涨到 1s。A 服务的重试策略是“超时 500ms 重试 2 次”。好了,现在每次请求在 A 端都要等待:第一次请求 500ms 超时,重试 1 次等 500ms 再超时,重试第 2 次等 500ms……一个请求就耗了 1.5s 以上。更可怕的是,A 服务的线程池很快被这些等待中的请求填满。新的请求进来直接排队,排队也超时,然后也重试……

你想想看,这像不像滚雪球?重试放大了负载,负载拖垮了下游,下游的故障又通过重试反向传播到上游。最终整个调用链全部瘫痪。这就是重试风暴导致的雪崩。

避坑指南:我曾经遇到过一个生产事故,就是因为网关层把超时设为 200ms,重试 3 次。后端数据库慢查询导致响应时间到了 300ms,结果网关层以为服务挂了,疯狂重试。后端 QPS 瞬间飙升 4 倍,直接打挂。事后复盘,发现重试带来的流量放大简直离谱。

防范雪崩的常见手段:

策略 做法 我推荐的适用场景
指数退避(Exponential Backoff) 每次重试间隔加倍。例如第一次等 200ms,第二次等 400ms,第三次等 800ms。 所有需要重试的地方,这是标配
限制最大重试次数 通常不超过 2~3 次。超过就快速失败,不要无限重试。 所有场景
熔断器(Circuit Breaker) 当失败率达到阈值,直接断开支路,快速返回失败,不再重试。 关键链路上的依赖调用
限流(Rate Limiting) 在上游对下游的调用做并发控制,防止瞬时重试风暴。 网关层、核心服务入口
请求透传/快速失败 部分场景不需要重试,直接告诉客户端“忙不过来”。 非关键操作,或负载已很高时

我个人最喜欢“指数退避 + 熔断器”组合。指数退避让重试间隔拉开,熔断器在连续失败后直接切断链路。两者加起来,即使下游挂了,上游也不会往死里打。

4.3 归纳对比:幂等 vs 雪崩

有时候新人会混淆这两个概念。说白了,幂等是解决“重试会不会造成数据错乱”,雪崩是解决“重试会不会把系统搞崩”。一个是数据一致性,一个是系统可用性。它们可以独立存在,但往往同时出现。

拿一个场景帮你想透:假设你做了一个短信发送服务,对外提供接口。如果下游短信网关超时,你决定重试。这时候,不解决幂等 → 用户收到多条重复短信。不解决雪崩 → 重试风暴把短信网关打挂,后面所有人的短信都发不出去。两条都得管。

总结一句:重试必须同时保证幂等性和防雪崩。缺了哪个,重试机制就是一把双刃剑,伤了别人也伤了自己。

4.4 本章知识体系图

下面这张图把重试可能引发的问题以及对应的解决方案串了起来。你一眼就能看到全局。

重试问题与应对策略 重试可能带来的问题与应对策略 重试机制 幂等性问题 重复扣款/订单 数据不一致 雪崩问题 重试风暴 链路级联故障 核心解决方案 幂等方案 幂等键 / 去重表 / 状态机 防雪崩方案 退避 / 熔断 / 限流 二者必须同时治理,缺一不可