百度抓取压力把服务器打满之后:Crawl-delay 与压力反馈工具的排查复盘
你将看到一次真实的百度爬虫压垮服务器事故,以及从日志到限流再到收录回升的完整排查过程。
上个月 14 号下午两点多,我们公司官网(制造业 B2B 站,大约四千个 URL)突然打不开,客服部电话被打爆。登上服务器一看,CPU 长期 90% 以上,带宽跑满 50Mbps,access.log 里密密麻麻全是 Baiduspider。那一小时的并发请求数是平时的七倍多。做网站优化(Search Engine Optimization, SEO)这几年,第一次被搜索引擎自己打到宕机。这篇就复盘整个过程,包括我们中途一个错误决定差点让收录崩掉。
事情怎么发生的
先交代背景。站点是 2019 年上线的老站,跑在一台 4 核 8G 的云服务器上,Nginx 1.24 + PHP-FPM,内容以产品页和技术资料页为主,平时日 PV 一万多,不算重负载。

出事前一周,我们刚把全站 URL 从动态参数改成了伪静态,并在百度搜索资源平台(ziyuan.baidu.com)提交了新版链接。改动后站点结构变了不少,旧 URL 301 到新 URL。问题就出在这:百度发现站点大面积变化后,临时调高了抓取频次来更新它的索引库。伪静态规则又写得比较费 CPU——每条请求都要跑一遍正则匹配再转发给 PHP——爬虫一提速,服务器直接顶不住。
这里得说清楚百度抓取压力的机制,不然后面的处理你看不明白。
百度抓取压力的机制
百度官方的说法是:Baiduspider 会根据网站规模、更新频率、页面质量、服务器承受能力来动态调整抓取频次。它有一条压力基线,理论上会「自动适配」站点的负载。但这个自动适配是滞后的——它感知到你的服务器变慢,需要先观察到一段时间的超时、5xx 响应,然后再往回调频次。回调窗口往往是小时级的,而一台小服务器被打满只要几分钟。
也就是说,抓取频次和站点负载之间存在一个反馈回路,但这个回路的响应速度跟不上突发调整。你在资源平台「抓取频次」工具里看到的曲线,是百度已经执行的结果,不是即将执行的预告。等你在曲线上看到尖峰,服务器早就被压过了。
另一个常被忽略的点:URL 改版、大量新链接提交、301 跳转集中上线,这些动作都会触发抓取频次上调。我们后来在站长社区看到不少人有类似经历,改版后一两周是压力最大的窗口期。
flowchart TD
A[站点改版/批量提交链接] --> B[百度上调抓取频次]
B --> C[请求量陡增]
C --> D{服务器能否承受}
D -- 承受住 --> E[索引更新正常]
D -- 承受不住 --> F[响应变慢/超时/5xx]
F --> G[百度感知异常]
G --> H[逐步下调频次]
H --> I[站点恢复]
F --> J[正常用户访问受阻<br/>业务受损]
排查:从日志确认元凶
服务器卡死的第一反应是被攻击,先排除了这个。看日志的命令很简单:
依赖:Linux 服务器(Ubuntu 22.04)、Nginx 1.24;以下命令均在生产机上以 root 执行。
# 统计最近一小时 UA 中含 Baiduspider 的请求数
grep "Baiduspider" /var/log/nginx/access.log | grep "$(date -d '1 hour ago' +'%d/%b/%Y:%H')" | wc -l
# 按分钟分组,看爬虫请求的时间分布,确认是持续高压还是脉冲式
awk '{print $4}' /var/log/nginx/access.log | grep "Baiduspider" | cut -d: -f1-3 | sort | uniq -c | sort -rn
# 查看爬虫请求里状态码分布,5xx 多说明服务器已经在硬扛
grep "Baiduspider" /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c
# 找出被请求最多的前 20 个 URL,判断爬虫在抓什么
grep "Baiduspider" /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
结果很典型:一小时 2.1 万次爬虫请求,其中 40% 打在旧的动态参数 URL 上,状态码里 301 和 502 混着来。正常用户的请求被挤到超时。元凶确认了,是百度,而且是奔着旧 URL 来的——它想尽快把改版后的索引对齐。
排查阶段我们还做了一张时间线表,方便后面复盘和对齐团队口径:
| 时间 | 现象 | 处理动作 | 结果 |
|---|---|---|---|
| D1 14:20 | CPU 90%+,带宽打满,用户无法访问 | 上全站 limit_req 每秒 5 请求 | 负载十分钟内恢复,但埋雷 |
| D4 | 索引量从 3800 掉到 1100,产品词排名下滑 | 撤掉全站限流,查资源平台曲线 | 确认抓取频次被压到 300 以下 |
| D5 | 服务器恢复但爬虫尖峰仍在 | 提交抓取压力反馈,频次上限调低一档 | 36 小时后抓取量回落 |
| D7 | 爬虫与用户争抢限流配额 | 上线 Nginx 双 zone 精细限流 | CPU 降到 40%,用户体验正常 |
| D20 | 索引量回升 | 持续观察频次曲线 | 收录超过事故前水平 |
我们踩的第一个坑:全站一刀切限流
运维同事小周(化名)当时很紧张,第一反应是「先把爬虫挡了再说」,直接在 Nginx 上加了一条全站 limit_req,对所有 UA 限到每秒 5 个请求。这招立竿见影,服务器负载十分钟内降下来了。
但三天后出问题了。我们在百度搜索资源平台的「抓取频次」工具里看到,频次曲线从每天 2 万多掉到了 300 以下,而且连续一周没回升。更要命的是索引量:原来首页和产品页在百度有 3800 多条收录,限流一周后掉到 1100。几个核心产品词的排名肉眼可见地下滑。销售部同事老陈跑来问「网站是不是被百度处罚了」。
后来复盘,这一刀切犯了两个错:
- 限流阈值定得太低。每秒 5 个请求,百度每天能抓的页面被压缩到 40 万以内都不到的水平——实际上大量请求被 503 拒绝,百度会把这些页面视为「暂时不可用」,从索引里移除或降权。
- 没有区分正常用户和爬虫的配额。正常用户的高峰请求和爬虫共享同一个 limit_req zone,等于爬虫和用户抢路。
sequenceDiagram
participant B as Baiduspider
participant N as Nginx(全站限流)
participant P as PHP-FPM
B->>N: 请求页面(高频)
N--xB: 超出阈值 返回503
Note over B: 连续503 判定站点不稳定
B->>B: 下调抓取频次+移除部分索引
N->>P: 正常用户请求(也受限流拖累)
P-->>N: 响应变慢
正确姿势一:用抓取压力反馈和频次工具沟通
踩坑之后我们换了思路。百度搜索资源平台其实提供了两条官方沟通渠道,很多人只知道其中一个。
「抓取频次」工具在「数据统计」栏目下,能看到百度每天、每小时对你站点的抓取量曲线,还能手动调节频次上限(分三档:强制上限、标准、不限制)。我们的做法是把频次上限先调到「标准偏低」一档,给服务器一个恢复窗口,等负载稳定后再逐步放开。
「抓取压力反馈」入口更关键。它允许站点管理员主动告诉百度「我的服务器目前承受不了当前抓取压力」,百度会安排下调。这个工具的价值在于它是双向的:不是被动等爬虫打满服务器,而是主动报备。我们提交反馈后大约 36 小时,抓取频次曲线明显回落到日常水平。
两种工具的差别我整理成一张表:
| 对比项 | 抓取频次工具 | 抓取压力反馈 |
|---|---|---|
| 位置 | 资源平台-数据统计 | 资源平台-网站支持/反馈入口 |
| 作用方向 | 查看+手动设定频次上限 | 主动告知服务器压力大 |
| 生效速度 | 设定后数小时 | 提交后约 1-2 天(我们实测 36 小时) |
| 适用场景 | 例行监控、改版前预防 | 突发过载、临时降载 |
| 副作用 | 上限过低会压制收录 | 无明显副作用,回调后自动恢复 |
顺带把 Crawl-delay 的口径也交代一下,这个话题坑过很多人。
Google 早在 2019 年就官方宣布不再使用 robots.txt 里的 Crawl-delay 指令,写了也是白写。百度官方文档同样没有声明支持 Crawl-delay,站长社区里有人实测有效、有人实测无效,百度工程师在公开场合的答复是「抓取压力请通过资源平台的工具沟通」。所以把服务器负载的希望寄托在 Crawl-delay 上是不可靠的,它是 Bing 等少数引擎支持的指令,对百度基本是心理安慰。
正确姿势二:Nginx 区分爬虫与用户的精细限流
全站一刀切不行,那就精细限。目标有两个:保住正常用户体验,同时把爬虫的压力控制在服务器能接受的范围内,别让百度以为站点不稳定。
依赖:Nginx 1.24(Ubuntu 22.04 的 apt 安装版),配置文件位于 /etc/nginx/;改动后需 nginx -t 验证再 reload。
# ---- 全局限流 zone 定义,必须放在 http 块 ----
# 用户区:按客户端 IP 限流,10MB 共享内存约可跟踪 16 万个 IP
limit_req_zone $binary_remote_addr zone=user_perip:10m rate=20r/s;
# 爬虫区:按百度 UA 限流,阈值明显高于用户区,保证抓取不被卡死
# $spider_is_baidu 是自定义 map 变量,见下方 map 块
limit_req_zone $spider_is_baidu zone=baiduspider:10m rate=50r/s;
# 用 map 把请求分成两类,爬虫命中爬虫键,其余命中用户键
map $http_user_agent $spider_is_baidu {
default "";
~*Baiduspider $binary_remote_addr;
}
# 抓取到的爬虫请求超出速率后先排队 20 个,再多的才拒绝
# burst 不宜过大,过大等于没限
limit_req zone=baiduspider burst=20 delay=8;
# 爬虫被限流时返回 503 而不是默认的 503 页面,同时加 Retry-After 头
limit_req_status 503;
server {
listen 443 ssl;
server_name www.example-mfg.cn;
# 用户请求:只对动态页面限流,静态资源不限,避免页面加载被拖慢
location ~ \.php$ {
limit_req zone=user_perip burst=40 nodelay;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
# 关键:给 PHP-FPM 设上限,防止慢请求把进程池占满
fastcgi_read_timeout 15s;
}
# 伪静态重写集中在这里,改用简单前缀匹配替代多条正则,降低 CPU 消耗
location /products/ {
# 命中前缀后内部跳转到固定入口,不做重复正则匹配
try_files $uri $uri/ /index.php?$query_string;
}
}
这套配置上线后的效果,以我们站点的实测数据说:爬虫高峰期的请求速率被稳定压在每秒 50 上下,服务器 CPU 从 90% 降到 40% 左右,正常用户页面首字节时间从打满时的 6 秒回到 300 毫秒以内。关键是百度的抓取没有被大量拒绝——limit_req 的 burst 和 delay 让正常频率下的爬虫请求基本无感,只有尖峰被削掉。
收录恢复与验证
限流调整后第四天,资源平台的索引量曲线止跌回升。第 12 天回到 3500 左右,第 20 天超过了事故前的水平。核心产品词排名在第 10 天前后陆续回来。抓取频次曲线也稳定在每天 1.5 万到 2 万之间,没有再出现打满服务器的尖峰。
这中间我们做对的一件事是改版前就该预估压力:旧 URL 有 301 跳转的页面,百度会按旧链接重抓一遍再跟到新地址,等于抓取量短期翻倍。如果重来一次,我们会在改版前一周先在资源平台把频次上限调低一档,分批提交链接,而不是一次性全量提交。
误区澄清与几句收尾
把常见误区列清楚:Crawl-delay 对 Google 完全无效,对百度也没有官方背书,别指望它;出事时用 robots.txt 屏蔽 Baiduspider 更不可取——robots 协议的 Disallow 是「不抓取」的意思,已收录页面会被逐渐移出索引,等于用 SEO 的命换服务器片刻安宁;全站统一限流是最容易踩的坑,用户和爬虫必须分开配额。服务器扛不住时,优先走资源平台的抓取压力反馈,那是官方承认的沟通渠道。
从更长的视角看,这套「抓取压力—服务器负载—索引收录」的平衡功夫,以后做生成式引擎优化(Generative Engine Optimization, GEO)时同样用得上——AI 引擎的爬虫一样会带来压力问题,服务器稳、抓取顺,内容才有被引用的前提。
你在百度抓取压力上踩过什么坑,或者用过哪些压爬虫的招,评论区聊聊。
参考与延伸
- 百度搜索资源平台-抓取频次说明:https://ziyuan.baidu.com/wiki/953
- 百度搜索资源平台-抓取诊断与压力沟通:https://ziyuan.baidu.com/site
- Nginx 官方文档 Module ngx_http_limit_req_module:https://nginx.org/en/docs/http/ngx_http_limit_req_module.html
- Google 搜索中心-Crawl-delay 不再被使用的说明:https://developers.google.com/search/blog/2019/04/changing-crawl-delay
关键词:百度抓取频次、Baiduspider、Nginx限流、Crawl-delay、制造业官网收录、网站优化、抓取压力反馈