指数退避的工作原理
出现临时故障后,客户端会等待一段时间再重试。每次连续失败都会按倍数增加延迟,通常为前一次的两倍,直至达到上限。假设基础延迟为 1 秒,等待时间可以是:
延迟 = min(30 s, 1 s × 2^重试次数)
重试 0 → 1 s
重试 1 → 2 s
重试 2 → 4 s
重试 3 → 8 s
设置上限可防止等待时间无限增长。生产环境中的客户端通常还会加入抖动,随机设置每次延迟时长,避免大量工作进程同时重试,再次引发流量激增。
何时应重试
并非每次请求失败都应该重试。
- 429 Too Many Requests: 如果响应中有
Retry-After标头,应按其要求等待。标头值可以是等待秒数,也可以是 HTTP 日期。否则应采用退避并降低请求频率。参见 429 Too Many Requests。 - 502、503 和 504 响应: 这些通常是临时的网关或服务故障,可能由网站、CDN 或代理返回。此时可以采用退避重试,尤其是 GET 等安全请求。参见 503 Service Unavailable。
- 连接故障: 连接超时或中断时可以考虑重试,但必须确保重复执行该操作是安全的。
- 403 和 407 响应: 如果网站拒绝访问,或代理凭据无效,反复尝试通常无法解决问题。出现 407 错误 时,需要修正认证信息。
既要设置最大重试次数,也要设置总时限。除非服务支持幂等键,否则不要重试非幂等的 POST 请求。
指数退避、线性退避与固定退避
限速是服务器执行的规则,退避则是客户端遇到失败或限制后的应对方式。
| 方法 | 等待模式 | 主要权衡 |
|---|---|---|
| 固定 | 每次等待相同时长 | 简单,但多个工作进程可能同时重试 |
| 线性 | 每次增加固定时长 | 高负载时增长较慢 |
| 指数 | 每次按倍数增加延迟 | 能迅速降低重试频率,但等待时间可能变得很长 |
代理场景下如何使用退避
先确认哪一方返回了错误。如果网站或 CDN 返回 429,应降低请求速度、遵循 Retry-After,并减少并发。轮换出口 IP 无法解除与账号、Cookie 或更大网段绑定的限制。
如果代理连接失败,改用另一个正常端点重试或许有效,但延迟时间必须设上限,以免工作进程让代理网关过载。记录状态码、响应标头、重试次数和响应来源,以区分目标网站的限制与代理错误。
常见问题
指数退避总是让延迟时间翻倍吗?
不一定。指数退避按倍数增加延迟,常用倍数是 2,但并非必须。基础延迟、倍数和最大上限取决于服务和工作负载。
指数退避是否应该加入抖动?
应该,尤其是在多个工作进程可能同时失败时。全抖动会在 0 到计算出的指数退避上限之间随机选择延迟时长,减少同步重试。
指数退避最多应重试多少次?
这取决于总时限和操作类型。达到预设尝试次数或经过预设时长后应停止重试,并遵循 API 或网站提供的重试指引。