重试既是"稳定手段",也是"成本放大器"
重试能救回瞬时故障 ✔,但也会**放大成本与延迟** ✗,甚至把上游彻底压垮 ✗(重试风暴 ✔)。
所以"该不该重试"要靠规则 ✔,而不是"失败就再来一次" ✗。
一、先分清四类失败
| 类型 | 例子 | 该不该重试 |
|---|---|---|
| 瞬时故障 | 连接重置、5xx、超时 | **该**(退避重试 ✔) |
| 限流 | 429 / 配额超限 | 该(**按建议等待**,别硬顶 ✔) |
| 参数错误 | 400、schema 不符 | **不该**(重试还是错 ✔) |
| 业务拒绝 | 权限不足、内容不合规 | **不该**(重试是骚扰 ✔) |
**分不清这四类,重试就是赌博** ✗。
二、重试的三条硬规则
1. **指数退避 + 抖动**(1s → 2s → 4s × 随机抖动 ✔)—— 避免所有客户端同时重试 ✔;
2. **上限要硬**(次数 ≤ 2~3、总时长 ≤ 10~15s ✔)—— 超过就交给降级链 ✔;
3. **只在幂等操作上重试** ✔(写操作要么幂等,要么先补偿再重试 ✔ —— 见接线那篇 ✔)。
三、绝对不要重试的三种情况
四、重试要可观测(最容易被忽略)
**要点**:重试成本必须**单列** ✗,否则它会被平均进总成本里看不见 ✔。
五、一个务实配置(可直接抄)
```
网络/5xx:重试 2 次,退避 1s/3s + 抖动,总上限 10s
限流(429):按 Retry-After 等待,最多 1 次
4xx 参数类:不重试,直接回错(带可读原因 ✔)
写操作:默认不重试;幂等写可重试 1 次,且用幂等键 ✔
熔断:错误率 > 50% 且持续 30s → 熔断 60s,半开后放 10% 探测
```
一条判据
> 你的重试**额外成本**占总成本多少 ✔?说不出来,说明重试既没被观测、也没被控制 ✗。