bigywater.tech
爬虫工程 · 32

哪些错误该重试:超时、5xx、4xx 的分类

“该不该重试”不只是一个次数问题,更是“重试什么”的问题:重试 404 是浪费,不重试 503 是遗憾。这篇构造 1000 个行为固定的 URL(瞬时故障和永久错误混合),在同一个本机服务器上比较五种重试策略的成功数和浪费的请求。

750 对 750
“任何失败都重试”与“白名单”两种策略的最终成功数——相同
500 对 0
这两种策略各自浪费在永久错误上的请求数
t503 [503, 200, 200]
“第 1 次 503”与永远 500 的页面,第一次响应时无法区分

五种策略

实测 · 本机执行输出
  每个 URL 最多尝试 3 次,重试间隔 0.01 秒,请求超时 0.2 秒,32 个线程
  策略                                    最终成功     服务器收到          其中浪费在永久错误上      耗时
  不重试                                400      1000               0    0.7 秒
  任何失败都重试                            750      1950             500    1.1 秒
  只重试网络错误(异常)                        550      1150               0    0.7 秒
  网络错误 + 所有 5xx                      700      1550             200    0.9 秒
  网络错误 + 408/425/429 + 502/503/504     750      1450               0    0.9 秒

不重试:400 个成功。只重试网络错误(超时、连接重置):550 个,漏掉了 5xx 和 429 的瞬时故障。网络错误加所有 5xx:700 个,但把永远 500 的页面也重试了 2 次(浪费 200 个请求)。任何失败都重试:750 个成功,但 1950 个请求里 500 个是浪费在 404/403/500 上的。白名单(网络错误、408/425/429、502/503/504):750 个成功,浪费为 0。

剩下失败的是谁

实测 · 本机执行输出
  不重试:p403 50, p404 100, p500 100, t429 50, t502 50, t503 100, treset 100, ttimeout 50
  任何失败都重试:p403 50, p404 100, p500 100
  只重试网络错误(异常):p403 50, p404 100, p500 100, t429 50, t502 50, t503 100
  网络错误 + 所有 5xx:p403 50, p404 100, p500 100, t429 50
  网络错误 + 408/425/429 + 502/503/504:p403 50, p404 100, p500 100

最后只剩永久错误(403、404、永远 500)没成功,这些重试多少次都不会成功。把状态码按“可能瞬时”和“基本永久”分类,就是为了不去重试后者。

500 的困境

实测 · 本机执行输出
  连续请求 3 次 /t503/1:[503, 200, 200]
  连续请求 3 次 /p500/1:[500, 500, 500]

永远 500 的页面和只失败一次的 503,第一次响应看起来一样,500 通常是服务器自己的 bug,但有时也是暂时的。重试它们就必须接受一定浪费,所以要限制次数(这里是 3 次)。

分步演示

重试什么
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / requests 2.34.2 / aiohttp 3.14.3 / lxml 6.1.1(系统 Python);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、断连、压缩、重定向等行为,并记录收到的原始请求;计时用 time.perf_counter,数字每次运行会有小幅抖动。服务器按路径前缀决定行为,并记录每个路径被请求的次数(第 1 次失败、之后成功的类别靠这个计数);连接重置用 SO_LINGER=0 关闭连接实现;客户端 requests.Session,请求超时 0.2 秒,32 个线程,每个 URL 最多尝试 3 次,重试间隔 0.01 秒;“浪费”=对永久错误 URL 超过首次请求的额外请求数
    • 没有验证:429 带 Retry-After 时的等待(上一篇);重试预算与断路器;真实站点里 403 有时是限流(被识别的结果)而不是永久禁止;幂等性与 POST(下一篇);不同重试间隔(这里固定 0.01 秒)对结果的影响;重试对服务器恢复的影响(上上篇)
    京ICP备2026067502号-1京公网安备11010502063487号