bigywater.tech
Scrapy · 39

scraper 的背压:SCRAPER_SLOT_MAX_ACTIVE_SIZE 与慢 pipeline

下载很快、处理很慢的时候,Scrapy 会不会把所有响应都堆在内存里?背压在哪里发生、阈值是多少、小响应怎么计?这篇用故意拖慢的回调,量出不同上限下滞留的响应数、内存和耗时。

5,000,000
SCRAPER_SLOT_MAX_ACTIVE_SIZE 的默认值(字节)
99.5 → 239.4 MiB
上限从 1 MB 放到 100 MB 时进程峰值 RSS
1024
每个响应在账本里至少计的字节数

账本与上限

实测 · 本机执行输出
  SCRAPER_SLOT_MAX_ACTIVE_SIZE = 1,000,000      峰值 active_size  2,400,312 字节;同时滞留的响应    24 个;进程峰值 RSS   99.5 MiB;总耗时 11.1 s
  默认 5,000,000                                  峰值 active_size  6,500,845 字节;同时滞留的响应    65 个;进程峰值 RSS  118.1 MiB;总耗时 3.8 s
  SCRAPER_SLOT_MAX_ACTIVE_SIZE = 20,000,000     峰值 active_size 21,202,756 字节;同时滞留的响应   212 个;进程峰值 RSS  170.8 MiB;总耗时 1.3 s
  = 100,000,000(基本不限)                           峰值 active_size 40,005,200 字节;同时滞留的响应   400 个;进程峰值 RSS  239.4 MiB;总耗时 0.9 s

响应进入 scraper 时 active_size 加上它的大小(至少 1024),回调、pipeline 处理完才减掉;一超过 SCRAPER_SLOT_MAX_ACTIVE_SIZE,引擎的 needs_backout() 为真,不再取调度器里的请求。上限越大滞留的响应越多、内存越高、总耗时越短。

什么时候起作用

实测 · 本机执行输出
  默认设置,回调不等待                                    峰值 active_size  2,500,325 字节;同时滞留的响应    25 个;进程峰值 RSS   98.2 MiB;总耗时 0.4 s

只有处理比下载慢才会堆积;回调、pipeline 都很快时,滞留量基本等于并发数,背压没有效果。

小响应

实测 · 本机执行输出
  默认 SCRAPER_SLOT_MAX_ACTIVE_SIZE = 5,000,000:峰值 active_size 1,047,552 = 1023 × 1024 + 0;同时滞留的响应 1023 个;进程峰值 RSS 258.7 MiB;总耗时 11.0 s
  SCRAPER_SLOT_MAX_ACTIVE_SIZE = 500,000:峰值 active_size 602,112 = 588 × 1024 + 0;同时滞留的响应 588 个;进程峰值 RSS 198.2 MiB;总耗时 13.0 s
  500,000 ÷ 1024 = 488 个;在途下载最多 100 个,所以峰值会超过一点

很小的响应按 1024 字节计费,所以大量小响应时按个数而不是按字节数限制。

分步演示

背压
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Scrapy 2.19.0 / Twisted 26.4.0 / lxml 6.1.3 / parsel 1.12.1(临时虚拟环境);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、重定向、压缩、断连等行为,并记录收到的原始请求;每个实验在临时目录里新建 Scrapy 项目或单文件 spider,命令输出来自真实的 scrapy 进程;计时用 time.perf_counter,数字每次运行会有小幅抖动。服务器立刻返回固定大小的页面;回调是 async def,await asyncio.sleep(…) 模拟慢处理;滞留数与 active_size 在每次 response_received 信号和 5 ms 的定时采样里取最大值;RSS 取 ru_maxrss(进程峰值,macOS 单位是字节)
    • 没有验证:慢 pipeline(而不是慢回调)是否同样占用账本;默认上限下 6000 个小页面只滞留到 1023 个而不是约 4,883 个的原因(没有追到);Linux 上的 RSS 读数;CONCURRENT_ITEMS = 1000 时耗时明显变长(试过一次,77 秒,没有深究);多个 spider 并行时每个 spider 一个账本(源码里是每个 spider 一个 Slot)
    京ICP备2026067502号-1京公网安备11010502063487号