一个爬虫同时抓很多个站点,其中有一个特别慢。它会拖住整个爬虫吗?答案取决于你怎么组织队列。这篇用三个速度差很多的本机站点,对比全局队列和按站点分队列,看快站点的完成时间、总耗时,以及每个站点收到的并发。
全部完成 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 秒。选哪个取决于你愿意让单个站点承受多大并发——本文没有任何真实站点的数据,只展示了取舍的形状。