bigywater.tech
爬虫工程 · 28

按域名分队列:一个慢站点会不会拖住整个爬虫

一个爬虫同时抓很多个站点,其中有一个特别慢。它会拖住整个爬虫吗?答案取决于你怎么组织队列。这篇用三个速度差很多的本机站点,对比全局队列和按站点分队列,看快站点的完成时间、总耗时,以及每个站点收到的并发。

3.1 对 0.4 秒
快站点 A 全部抓完的时间:全局队列里慢站点排前面 对 每站点独立队列
10
全局队列 10 个 worker 时,慢站点收到的并发峰值(独立队列时是 3)
4.2 对 10.0 秒
全局队列与每站点 3 个 worker 的总耗时

全局队列的队头阻塞

实测 · 本机执行输出
  全部完成 4.8 秒;A(快站点,100 个)全部完成于 3.8 秒,中位完成时刻 1.6 秒;C(中等,100 个)完成于 3.9 秒;B(慢站点,30 个)完成于 4.8 秒;各站点收到的并发峰值 A=4 C=9 B=10

所有站点的 URL 混在一个先进先出队列、10 个 worker 共享时,慢站点的请求会占住 worker:慢站点排在最前面,快站点的 100 个 URL 要等到 3.1 秒才开始处理完;快站点排前面则 0.1 秒就完成。快站点什么时候完成,取决于它在队列里的位置。

按站点分队列

实测 · 本机执行输出
  慢站点 B 排最前:全部完成 4.2 秒;A(快站点,100 个)全部完成于 3.1 秒,中位完成时刻 3.1 秒;C(中等,100 个)完成于 4.2 秒;B(慢站点,30 个)完成于 3.0 秒;各站点收到的并发峰值 A=10 C=10 B=10
  快站点 A 排最前:全部完成 4.2 秒;A(快站点,100 个)全部完成于 0.1 秒,中位完成时刻 0.1 秒;C(中等,100 个)完成于 1.2 秒;B(慢站点,30 个)完成于 4.2 秒;各站点收到的并发峰值 A=10 C=10 B=10

每个站点一个队列、各自固定数量的 worker,站点之间互不影响:快站点 A 恒定 0.4 秒完成,无论 URL 顺序。每个站点收到的并发也就是它的 worker 数(这里是 3),不会出现“10 个 worker 全部打到同一个站点”。

代价

实测 · 本机执行输出
  慢站点 B 排最前:全部完成 10.0 秒;A(快站点,100 个)全部完成于 0.4 秒,中位完成时刻 0.2 秒;C(中等,100 个)完成于 3.6 秒;B(慢站点,30 个)完成于 10.0 秒;各站点收到的并发峰值 A=3 C=3 B=3
  快站点 A 排最前:全部完成 10.0 秒;A(快站点,100 个)全部完成于 0.4 秒,中位完成时刻 0.2 秒;C(中等,100 个)完成于 3.5 秒;B(慢站点,30 个)完成于 10.0 秒;各站点收到的并发峰值 A=3 C=3 B=3

按站点限并发后,慢站点成了总时间的下限:30 个 1 秒的请求在 3 个并发下需要 10 秒,而全局队列让它用到 10 个并发,4.2 秒完成。这个差别不是调度的 bug,而是对那个站点压力更小的直接代价。

怎么选并发数

实测 · 本机执行输出
  每个站点 1 个 worker(共 3 个并发):全部完成 30.1 秒;A(快站点,100 个)全部完成于 1.2 秒,中位完成时刻 0.6 秒;C(中等,100 个)完成于 10.3 秒;B(慢站点,30 个)完成于 30.1 秒;各站点收到的并发峰值 A=1 C=1 B=1
  每个站点 3 个 worker(共 9 个并发):全部完成 10.0 秒;A(快站点,100 个)全部完成于 0.4 秒,中位完成时刻 0.2 秒;C(中等,100 个)完成于 3.5 秒;B(慢站点,30 个)完成于 10.0 秒;各站点收到的并发峰值 A=3 C=3 B=3
  每个站点 6 个 worker(共 18 个并发):全部完成 5.0 秒;A(快站点,100 个)全部完成于 0.2 秒,中位完成时刻 0.1 秒;C(中等,100 个)完成于 1.8 秒;B(慢站点,30 个)完成于 5.0 秒;各站点收到的并发峰值 A=6 C=6 B=6

每站点 1、3、6 个 worker 的总时间是 30.1、10.0、5.0 秒。选哪个取决于你愿意让单个站点承受多大并发——本文没有任何真实站点的数据,只展示了取舍的形状。

分步演示

按域名分队列
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。三个本机服务器模拟站点 A、C、B(每个请求分别停 0.01、0.1、1.0 秒);URL 数量 A 100、C 100、B 30;全局队列是一个 asyncio.Queue 加 10 个 worker;按站点分队列是每个站点一个 asyncio.Queue 加固定数量的 worker;各站点的并发峰值由对应服务器统计;每种配置各跑一次,打乱顺序用固定随机种子 1
    • 没有验证:更复杂的调度(轮询选择站点、按优先级、动态调整每站点并发);站点在运行中变慢或超时时的自适应(如 Scrapy 的 AutoThrottle,属于另一个系列);对同一个站点跨多个域名(CDN、子域名)的归并;URL 很多但站点很少时队列的内存开销;真实站点的响应时间分布
    京ICP备2026067502号-1京公网安备11010502063487号