重试与退避是什么
重试与退避是对可重试的瞬时故障按延迟递增策略再次尝试。指数退避叠加随机抖动可以避免多个客户端同时重试形成同步风暴;它必须与超时、次数上限和幂等设计一起使用,否则重试本身就是故障放大器。
什么该重试
网络错误、连接超时、服务端过载以及幂等写冲突都值得重试;参数错误、鉴权失败与业务规则拒绝不该重试,重试不会改变结果,只会浪费资源并延迟错误暴露。非幂等的请求在重试前必须先确认服务端是否已经执行过,否则会重复下单或重复扣款。
退避算法
退避算法
delay = min(cap, base * 2^attempt) # 指数增长,设上限
jitter = random(0, delay) # 抖动,避免同步重试
sleep(jitter)
# 可重试:网络错误、连接超时、过载、幂等写冲突
# 不重试:参数错误、鉴权失败、业务规则拒绝
# 上限:同时限制次数与总耗时,避免占用线程过久重试判断
| 情形 | 是否重试 | 说明 |
|---|---|---|
| 连接超时 | 是 | 退避后重试,注意次数上限 |
| 请求超时 | 看情况 | 非幂等操作需先确认服务端是否已执行 |
| 服务端过载 | 是 | 需区分过载与逻辑错误,遵循服务端返回的等待时间 |
| 参数或鉴权错误 | 否 | 重试不会改变结果 |
| 写冲突 | 是 | 幂等操作可在短退避后重试 |
重试与取消的边界
重试要和超时、取消一起考虑:如果外层已经超时返回,内层还在继续重试,用户拿到失败结果的同时服务端仍在消耗资源。更麻烦的是迟到成功,业务侧已经按失败处理并回滚,下游却完成了一次写入。因此重试必须在超时预算内收敛,并把非幂等操作排除在自动重试之外。
层次叠加要警惕:客户端、网关、服务各层都做重试时,放大倍数相乘,下游在故障恢复瞬间可能被重试流量再次击穿。约定只有一层负责重试。