★ 超时、重试怎么设计才不拖垮系统?指数退避与抖动是什么?

结论先行:调用外部系统必须先设超时——连接、读、总超时分层设;重试只允许在“幂等 + 可重放”的请求上,且必须配合指数退避与随机抖动,否则一次故障会因固定间隔重试放大成流量雪崩。超时、重试、熔断必须一起设计(见第 43 章)。

一、超时三件套

// Java HTTP 客户端示例
.connectTimeout(500ms)    // 建连超时
.readTimeout(1000ms)      // 读响应超时
// 调用级总超时:整体 2s,超过直接失败返回
  • 原则:每一层都设,别指望对端良心;超时从调用方视角按接口 P95 定。
  • 超时传递:上游把剩余预算传下去(如 gRPC deadline),防止层层各等各的超时。

二、重试的代价模型

后端故障时:
固定重试 3 次 × 1 万调用 = 4 万次请求同时压向故障节点 → 雪崩
维度正确做法错误做法
场景幂等操作(查询、幂等写)非幂等扣款/下单直接重试
间隔指数退避 + 抖动固定 1s 同步重试
上限明确次数与总时长无限重试
配合熔断后停止重试无视熔断状态继续打

三、指数退避 + 抖动

第 n 次等待 = min(base * 2^n, cap) + random(0, jitter)
例:base=200ms, cap=5s → 0.2s → 0.4s → 0.8s → 1.6s → 5s
  • 退避让单请求次数可控;抖动让不同调用方错峰,避免同一时刻集体重试打爆系统。
  • 客户端重试要有“重试预算”:总次数与总时间双上限(如最多 3 次、全程 ≤ 30s)。

常见追问与记忆点

  • 追问:超时时间怎么定才不误伤?看接口 P95/P99 耗时基线,超时设为其 2~3 倍并留余量。
  • 追问:重试与幂等怎么配合?重试请求要带幂等键,服务端按键去重,才能安全重放。
  • 记忆点:没设超时的调用是定时炸弹;重试 = 幂等 + 指数退避 + 抖动 + 次数上限 + 熔断联动。
笔记加载中…