本文约 3,120 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:先是偶尔打不开,后来是收录慢慢掉
这类故障的进程很像慢性病:最开始只是高峰期偶尔 502,刷新一下又好;过两周,用户反馈变多,日志里 504 开始成批出现;再过一个月,资源平台的索引量曲线掉头向下,抓取频次从每天几千降到几百,新发布的文章要五六天才被抓一次。这期间站点内容没变、外链没动,唯一变化就是稳定性。很多站长到这一步还在优化标题和关键词,方向完全错了。百度对不可靠站点的处理是渐进式的:错误率上升 → 抓取频次下调 → 新内容抓取延迟 → 索引更新滞后 → 快照回退旧版本 → 整体收录下滑。它不是「惩罚」,而是资源调度层面的主动规避,所以修复方式也不是申诉,而是先把服务器修好,再等爬虫自己回来。
原理分析:错误率如何转化为抓取频次削减
Baiduspider 的调度器会给每个站点维护一个「健康度」评估,其中最敏感的两个输入是超时率和5xx 占比。一次抓取超时的成本比一次 404 高得多,因为连接占用时间长。当失败比例超过阈值,调度器不会停止抓取,而是降低并发与频次,把资源让给响应正常的站点。这个过程的副作用是:你的页面即使修好了,调度器也不会立刻恢复原频次,它需要连续若干轮成功抓取才会逐步上调,这就是「修复后还要等」的原因。
| 阶段 | 表现 | 可逆性 |
|---|---|---|
| 错误率上升 | 日志 5xx 增多 | 可逆,立即修 |
| 频次下调 | 抓取量减少、新页延迟 | 可逆,需 1–2 周 |
| 索引滞后 | 快照旧、更新不生效 | 可逆,需 2–4 周 |
| 收录下滑 | 索引量持续降 | 可逆,需 4–8 周 |
| 长期不可达 | 整站被判死站 | 恢复代价极大 |
关键判断点:如果只是收录下降但抓取频次正常,那多半是内容或改版问题,不是稳定性问题。反过来,抓取频次骤降且日志里 5xx 占比高,才把稳定性列为第一嫌疑。
保姆级实操
步骤 1:先量化故障,不要凭印象。 从 nginx 访问日志统计状态码分布,并按小时看峰值:
LOG=/var/log/nginx/access.log
echo "== 整体状态码分布 =="
awk '{print $9}' "$LOG" | sort | uniq -c | sort -rn | head -10
echo "== Baiduspider 抓到的状态码 =="
grep 'Baiduspider' "$LOG" | awk '{print $9}' | sort | uniq -c | sort -rn
echo "== 按小时统计 5xx =="
awk '$9>=500 {split($4,a,":"); print a[2]}' "$LOG" | sort | uniq -c
步骤 2:加一个每分钟探测的监控,把故障时间点记录下来。 有时间点才能和资源平台的抓取曲线对上:
#!/usr/bin/env bash
# /usr/local/bin/probe_site.sh 每分钟探测一次,异常写入日志
URL='https://mimangfei.com/health'
LOG=/var/log/site_probe.log
read -r code total < <(
curl -sS -o /dev/null -w '%{http_code} %{time_total}' --max-time 8 "$URL"
)
if [ "$code" != "200" ]; then
printf '%s code=%s cost=%ss\n' "$(date '+%F %T')" "$code" "$total" >> "$LOG"
fi
配合 crontab 每分钟执行一次:* * * * * /usr/local/bin/probe_site.sh。
步骤 3:针对性调整 php-fpm 进程池。 WordPress 的 502 大多是 php-fpm 进程耗尽或单请求超时导致的,不是 nginx 的问题:
; /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
; 每个子进程处理 500 个请求后重启,缓解内存泄漏
pm.max_requests = 500
; 单请求硬超时,避免慢查询拖死整个进程池
request_terminate_timeout = 30s
slowlog = /var/log/php8.2-fpm.slow.log
request_slowlog_timeout = 5s
pm.max_children 不是越大越好,按「可用内存 ÷ 单进程平均内存」估算,设太大反而触发 OOM。
步骤 4:给百度留一条稳定的通路。 在故障期间,静态资源与 sitemap 不应跟着一起挂。把 sitemap 生成为静态文件,用 nginx 直接返回,绕开 PHP。
步骤 5:修复后主动推送,加速恢复。 用抓取诊断连续抽查 10 个页面,全部返回 200 且正文完整后,通过 API 主动提交与 sitemap 重新提交,把新链接重新送到百度面前。不要一次性把全站几万条 URL 灌进 API,配额用尽反而浪费。
步骤 6:设定恢复观察表。 每周记录抓取频次、索引量、日志 5xx 占比三项,连续三周趋势向上即判定恢复中。
常见踩坑
- 故障时第一反应是重启服务器,重启完日志被清空,事后完全无法归因。
- 案例: 某站在双十一促销期间并发打满,php-fpm 进程池耗尽开始返回 502,运维只加了
pm.max_children却没设request_terminate_timeout,一个慢查询把新扩的进程也全占住,故障持续三天,抓取频次从日均 6000 掉到 400,恢复用了整整七周。 - 监控只测首页,首页命中缓存一直 200,文章页早就 500 了。
- 用 CDN 后,源站故障被 CDN 缓存掩盖,但 CDN 缓存过期时百度正好来抓,抓到 502。
- 修复后立刻大量外链,试图「补权重」,其实此时问题在抓取不在权重,白花钱。
- 只看 5xx,忽略 200 但响应 30 秒的软超时,这类在日志里体现为 upstream response time 极高。
- 健康检查接口
/health返回 200 但站点实际不可用(比如只检查了 nginx 没检查 PHP),监控形同虚设。
总结
判断是否因稳定性被降权,看两个配对数据:日志 5xx 占比是否超过 0.5%,且资源平台抓取频次是否同步下调。两者同时成立,才按稳定性问题处理。行动清单:日志量化 → 加分钟级探测 → 调 php-fpm 进程池与超时 → 静态化 sitemap 保通路 → 修复后抓取诊断验证 → 分批主动推送 → 每周记录三项指标等到回升。稳定性是所有 SEO 动作的地基,地基不稳时做任何优化都无效。速度层面的量化方法见 网站速度对百度收录的影响,收录异常的整体排查顺序见 百度收录下降排查流程。
