重试与退避

对可重试的瞬时故障按延迟递增策略再次尝试;指数退避叠加随机抖动可避免同步重试风暴,必须配合超时、次数上限与幂等设计。

重试与退避是什么

重试与退避是对可重试的瞬时故障按延迟递增策略再次尝试。指数退避叠加随机抖动可以避免多个客户端同时重试形成同步风暴;它必须与超时、次数上限和幂等设计一起使用,否则重试本身就是故障放大器。

什么该重试

网络错误、连接超时、服务端过载以及幂等写冲突都值得重试;参数错误、鉴权失败与业务规则拒绝不该重试,重试不会改变结果,只会浪费资源并延迟错误暴露。非幂等的请求在重试前必须先确认服务端是否已经执行过,否则会重复下单或重复扣款。

退避算法

退避算法
delay = min(cap, base * 2^attempt)     # 指数增长,设上限
jitter = random(0, delay)               # 抖动,避免同步重试
sleep(jitter)

# 可重试:网络错误、连接超时、过载、幂等写冲突
# 不重试:参数错误、鉴权失败、业务规则拒绝
# 上限:同时限制次数与总耗时,避免占用线程过久

重试判断

情形是否重试说明
连接超时是退避后重试,注意次数上限
请求超时看情况非幂等操作需先确认服务端是否已执行
服务端过载是需区分过载与逻辑错误,遵循服务端返回的等待时间
参数或鉴权错误否重试不会改变结果
写冲突是幂等操作可在短退避后重试

重试与取消的边界

重试要和超时、取消一起考虑:如果外层已经超时返回,内层还在继续重试,用户拿到失败结果的同时服务端仍在消耗资源。更麻烦的是迟到成功,业务侧已经按失败处理并回滚,下游却完成了一次写入。因此重试必须在超时预算内收敛,并把非幂等操作排除在自动重试之外。

层次叠加要警惕:客户端、网关、服务各层都做重试时,放大倍数相乘,下游在故障恢复瞬间可能被重试流量再次击穿。约定只有一层负责重试。

易错点

  • 重试无次数上限,故障恢复后下游又被重试流量击穿
  • 非幂等接口盲目重试,产生重复扣款或重复下单
  • 重试不带抖动,所有客户端同时重试形成同步脉冲
  • 多层同时重试,实际放大倍数远超设计预期
  • 重试占用的线程不设超时,慢下游把线程池慢慢耗尽

数据来源与参考

  • AWS 架构博客:Timeouts, Retries, and Backoff with Jitter
  • Google SRE Book:Handling Overload
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌