ByFomo

架构实战|降级与熔断:让系统学会“认怂”,才能扛住流量与故障(连载第 8 篇)

2026/02/04
0
0

---

## 12. 进阶补丁:重试、抖动、以及“别把下游当砂锅”

讲熔断不讲重试,就像讲健身不讲饮食——容易练出“看起来很努力,实际上很虚”的架构。

### 12.1 什么时候该重试?

建议用**可重试错误清单**,别靠感觉:

- 网络瞬断、连接 reset、DNS 抖动 → 可重试(次数少)

- 下游返回 429/503(明确限流)→ 先退避再重试(最好尊重 Retry-After)

- 业务校验失败(参数不合法、余额不足)→ 不要重试

- 下游超时(你已经等到预算上限)→ 通常不要同步重试,改走异步补偿

### 12.2 指数退避 + 抖动(Jitter)

没有抖动的重试,会让雪崩更整齐、更壮观。

```java

long base = 20; // ms

for (int i = 0; i < 2; i++) {

try {

return riskClient.check(req);

} catch (IOException e) {

long sleep = (long) (base * Math.pow(2, i));

long jitter = ThreadLocalRandom.current().nextLong(0, 10);

Thread.sleep(sleep + jitter);

}

}

throw new DownstreamException("risk retry failed");

```

记住:在交易主链路里,重试次数宁可少,宁可让系统快速失败,然后由异步流程把事办完。

---

## 13. 返回码与前端协作:降级不是“随便回一句”

降级后的返回,必须让客户端知道“现在发生了什么”。

一个实用的约定:

- `OK`:已成功创建订单

- `PROCESSING`:已受理,结果稍后确认(配合查询接口/通知)

- `RETRY_LATER`:系统繁忙,请稍后再试(可引导排队/限流页面)

- `FAIL`:明确失败(风控拒绝/库存不足/余额不足)

并且在响应里放一个 `traceId`,让客服别再拿“截图”逼你破案:

```json

{

"code": "PROCESSING",

"message": "系统繁忙,订单已受理,正在确认结果",

"orderId": "20260204000123",

"traceId": "0af7651916cd43dd8448eb211c80319c"

}

```

这比“HTTP 200 + message=success”成熟太多。

---

## 14. 最后一句:韧性不是写在 PPT 上,是写在‘被打爆的夜里’

你可以不喜欢‘降级’这个词,它听起来像妥协。

但交易系统的现实就是:

- 世界不总是 99.99% 的

- 下游不总是你的

- 流量不总是可预测的

所以我们要把系统训练成一种很成人的性格:

> 能拼的时候拼;拼不过的时候,先把自己活下来。

(连载未完,下一篇见。)