没有不值得去解决的问题,也没有不值得去学习的技术!

一次 WordPress 502 故障排查:18,455 个 Sogou UA 请求如何打满 1 核 ECS

图2:阿里云 ECS 状态与报警页面,CPU 达到实例规格上限累计报警 30 次。

作者:

最近我的 WordPress 博客突然开始频繁出现 502 Bad Gateway

最开始,我第一反应是服务器配置是不是已经不够用了。

毕竟目前这台阿里云 ECS 的配置并不高:

  • 1 核 vCPU
  • 2 GiB 内存
  • 2 Mbps 固定公网带宽
  • 20 GiB SSD 系统盘
  • Alibaba Cloud Linux 3
  • Nginx + PHP-FPM
  • Redis 运行在 ECS 本机
  • MySQL 使用阿里云 RDS,并不运行在这台 ECS 上

博客本身已经运行很多年,文章数量也越来越多。再加上最近一直在处理历史文章迁移、摘要生成、多语言翻译等工作,因此看到 502 后,我一度认为,可能终于到了需要把 ECS 从 1 核 2G 升级到 2 核 4G 的时候。

但后面的排查结果证明:

这次 502 的核心问题,并不是正常业务已经超出了 1 核 2G 的能力,而是一批异常高频、携带 Sogou web spider User-Agent 的访问,把 PHP-FPM 和 CPU 直接压到了极限。

而且整个故障从严重 502,到 EdgeOne 拦截后迅速恢复,过程非常典型。


一、故障现象:WordPress 后台开始间歇性 502

问题最明显的表现,是访问:

Plaintext
admin.shuijingwanwq.com/wp-admin/

时,开始间歇出现:

Plaintext
502 Bad Gateway
nginx
图1:WordPress 后台访问时出现 Nginx 502 Bad Gateway。
图1:WordPress 后台访问时出现 Nginx 502 Bad Gateway。

我尝试重启 ECS。

刚重启后网站会暂时恢复,但过一会儿又重新开始出现 502。

这就意味着问题不像单纯的某个服务偶发挂掉:

Plaintext
重启
→ 暂时正常
→ 负载重新上升
→ 再次 502

与此同时,阿里云 ECS 控制台已经记录到了大量 CPU 性能异常。

一天内出现了 30 次:

Plaintext
实例的 CPU 性能达到规格上限
图2:阿里云 ECS 状态与报警页面,CPU 达到实例规格上限累计报警 30 次。
图2:阿里云 ECS 状态与报警页面,CPU 达到实例规格上限累计报警 30 次。

这时已经可以确认:

服务器确实存在持续性的资源压力,而不是浏览器或者网络偶发错误。


二、一开始怀疑是不是清除服务器缓存导致的

问题出现前,我确实执行过一次服务器端缓存清理。

不过这里必须明确区分两层缓存。

我的网站架构大致是:

Plaintext
访客

EdgeOne / Cloudflare

Nginx

W3 Total Cache / Redis

PHP-FPM

WordPress

阿里云 RDS

我清除的是服务器上的 W3TC Page Cache、Object Cache 等缓存。

并没有清除 EdgeOne 和 Cloudflare 的 CDN 边缘缓存。

因此不能简单理解成:

Plaintext
清服务器缓存
→ CDN 全部 MISS
→ 所有用户突然回源
→ ECS 被打爆

这个因果关系是不成立的。

已有的 CDN HIT 仍然会继续由边缘节点直接返回。

服务器缓存被清空,只会增加那些原本就需要回源的请求的处理成本,比如:

  • CDN 自然 MISS
  • CDN TTL 到期后的首次回源
  • WordPress 后台
  • REST API
  • WP-Cron
  • 登录用户请求
  • 动态请求

所以缓存清理可能是某个时间点上的影响因素,但不能直接解释持续一天的严重 502。

必须继续找真正的资源消耗者。


三、抓现场:Load 已经达到 9,CPU 完全没有空闲

重启服务器后大约 17 分钟,我开始直接检查系统状态。

结果非常夸张:

Plaintext
load average: 9.22, 9.55, 6.79

对于只有 1 核 CPU 的服务器来说,这个负载已经非常高。

继续看 vmstat

Plaintext
us  sy  id  wa
91   9   0   0
92   8   0   0
92   8   0   0
92   8   0   0
92   8   0   0

CPU idle 连续为:

Plaintext
0%

而且 iowait = 0

也就是说:

CPU 不是在等待磁盘,也不是单纯卡在网络 I/O,而是真正在持续执行用户态程序。

图3:服务器负载达到 9.x,vmstat 显示 CPU idle 持续为 0%。
图3:服务器负载达到 9.x,vmstat 显示 CPU idle 持续为 0%。

四、真正吃满 CPU 的是 PHP-FPM

接下来检查 CPU 占用最高的进程。

结果非常整齐:

Plaintext
php-fpm  13.3%
php-fpm  13.3%
php-fpm  13.3%
php-fpm  13.3%
php-fpm  13.0%
php-fpm  12.9%
php-fpm  12.9%

总共 7 个 PHP-FPM Worker。

而 Redis 只有大约:

Plaintext
1.8%

Nginx 也只有:

Plaintext
0.9%

所以这次 ECS CPU 压力的主要来源已经很明确:

PHP-FPM。

与此同时,服务器上的 PHP-FPM 配置是:

Plaintext
pm.max_children = 7
pm.max_requests = 500
request_terminate_timeout = 600s
request_slowlog_timeout = 3s

也就是说,7 个 Worker 已经全部在高负载工作。

更严重的是 PHP-FPM Socket:

Plaintext
LISTEN 510 511 /dev/shm/php-cgi.sock

等待连接队列已经达到:

Plaintext
510 / 511

只差 1 个位置就完全塞满。

这已经足够解释为什么 Nginx 会返回 502:

Plaintext
Nginx

PHP-FPM 7 个 Worker 全忙

新的 PHP 请求不断进入

FastCGI 队列持续积压

510 / 511

请求超时、失败

502 / 499

五、不是内存问题,也不是 RDS 在本机吃 CPU

这次还有一个很容易误判的地方。

服务器只有 2 GiB 内存,但现场其实还有:

Plaintext
available ≈ 1.2 GiB

Swap 基本没有使用,也没有发现:

Plaintext
OOM
Out of memory
Killed process

所以这次不是典型的内存耗尽。

另外,我的 MySQL 使用的是阿里云 RDS,并没有运行在 ECS 本机。

因此不存在:

Plaintext
mysqld 90% CPU

这种情况。

服务器本地真正值得关注的是:

Plaintext
PHP-FPM
Redis
Nginx

而现场已经明确指向 PHP-FPM。


六、直接从 127.0.0.1 请求后台,照样大量 502

为了排除公网、DNS、EdgeOne、Cloudflare 等因素,我直接让 ECS 本机访问:

Plaintext
127.0.0.1

Nginx

PHP-FPM

WordPress

连续测试 20 次。

结果非常惨。

有的请求:

Plaintext
HTTP=502
total≈0.1 秒

还有大量请求:

Plaintext
HTTP=000
15 秒超时

整个 20 次测试中,没有正常恢复。

这一步基本把外部网络因素排除了。

问题就在:

Plaintext
ECS
Nginx
PHP-FPM
WordPress

这一条内部链路里。


七、真正的突破口:最近 20,000 条请求中,18,455 条都是 Sogou UA

继续分析 Nginx 访问日志后,终于发现了真正异常的地方。

最近 20,000 条 www 请求,状态码统计为:

Plaintext
11925  499
7551   502
296    301
148    200
43     404
29     500

也就是说:

真正成功返回 200 的请求,只剩 148 条。

大量请求已经变成 499 和 502。

但更加惊人的是 User-Agent:

Plaintext
18455 Sogou web spider/4.0

最近 20,000 条请求中,18,455 条都是:

Plaintext
Sogou web spider/4.0

占比超过:

Plaintext
92%

其他 Googlebot、Bingbot、Baiduspider、真实浏览器访问,与它相比几乎都只是零头。

图4:最近 20,000 条访问日志中,Sogou web spider 占据绝大多数请求。
图4:最近 20,000 条访问日志中,Sogou web spider 占据绝大多数请求。

八、每分钟 500~700 个请求,持续遍历大量不同页面

再按照分钟统计请求量:

Plaintext
14:01  546
14:02  623
14:04  724
14:05  678
14:09  595
14:13  638
14:14  609
14:22  592
14:25  604
14:29  572

长期维持在:

Plaintext
500~700 次/分钟

也就是大约:

Plaintext
8~12 次/秒

而且不是疯狂刷新同一个 URL。

它们在遍历:

Plaintext
文章页
分类页
分页
?p=xxxx
带 query 参数的页面

单个 URL 的请求量通常只有个位数或者十几次。

这意味着它更像是在:

高频遍历整个网站。

对于 CDN 来说,10 RPS 算不上什么巨大的攻击。

但对于:

Plaintext
1 核 CPU
+
WordPress 动态 PHP
+
每次执行可能达到 3 秒以上
+
pm.max_children = 7

却完全足够把源站压垮。


九、来源 IP 也非常分散

再看来源 IP:

Plaintext
117.40.82.101
117.40.82.170
125.94.249.28
1.71.146.14
222.79.117.159
222.79.116.117
1.71.147.232
1.71.147.97
125.94.249.39
122.246.2.213
……

很多 IP 单独就出现了接近 1,000 次请求。

这也意味着:

单纯按照某一个 IP 做限速或者封禁,效果可能并不好。

真正高度统一的是:

Plaintext
User-Agent: Sogou web spider/4.0

十、这些到底是不是真正的搜狗爬虫?

我其实很疑惑。

一个成熟的搜索引擎爬虫,在服务器已经持续返回大量 502 的情况下,理论上应该会降低抓取速度,而不是继续维持高频抓取。

所以我对这些请求是否真的来自 Sogou 产生了怀疑。

我抽取了 10 个最高频的来源 IP 做 PTR 反查:

Plaintext
117.40.82.101
117.40.82.170
125.94.249.28
1.71.146.14
222.79.117.159
222.79.116.117
1.71.147.232
1.71.147.97
125.94.249.39
122.246.2.213

结果全部是:

Plaintext
PTR: 无

因此这些 IP 无法通过 DNS 反向解析验证为真正的 Sogou Spider

但这里我不会直接下结论说:

它们一定是假搜狗爬虫。

更严谨的描述应该是:

这是一批使用 Sogou web spider/4.0 User-Agent,但无法验证为搜狗官方 Spider 的异常高频流量。

User-Agent 本身完全可以伪造。

所以目前最重要的不是追究它们到底是谁,而是先保护生产服务器。


十一、在 EdgeOne 直接屏蔽 *Sogou*

因为我的中文主站已经使用 EdgeOne,所以最有效的止血位置不是 Nginx,而是:

直接在 CDN 边缘节点拦截。

我在 EdgeOne:

Plaintext
安全防护
→ Web 防护
→ 自定义规则
→ 基础访问管控

创建:

Plaintext
规则名称:
屏蔽 Sogou 爬虫

匹配字段:
User-Agent

匹配方式:
通配符匹配

匹配内容:
*Sogou*

执行处置:
拦截
图5:EdgeOne 创建 User-Agent *Sogou* 拦截规则。
图5:EdgeOne 创建 User-Agent *Sogou* 拦截规则。

规则发布后,在站点级防护策略中已经显示启用。

图6:EdgeOne 的“屏蔽 Sogou 爬虫”规则已经正式启用。
图6:EdgeOne 的“屏蔽 Sogou 爬虫”规则已经正式启用。

这里不需要清理 EdgeOne CDN 缓存。

安全规则和 CDN 内容缓存是两件不同的事情。


十二、屏蔽以后,服务器负载迅速开始下降

规则发布以后,大约几分钟时间,服务器状态就发生了非常明显的变化。

屏蔽前:

Plaintext
load average:
9.47, 9.63, 8.14

第一次复查:

Plaintext
3.11, 7.68, 8.58

再过几分钟:

Plaintext
2.69, 5.34, 7.31

随后:

Plaintext
1.81, 4.53, 6.88

1 分钟 Load 已经从接近 10 快速降到了不到 2。

由于 5 分钟和 15 分钟 Load 带有之前高负载时期的历史数据,所以下降速度会更慢,这是正常现象。


十三、Sogou 从 92% 直接降到 0

规则刚发布后的最近 200 条请求中:

Plaintext
Sogou = 16

已经从之前的 92% 下降到了很低的比例。

继续等待几分钟,再检查最近 100 条:

Plaintext
Sogou = 0

200 = 71
301 = 22
304 = 1
403 = 3
404 = 3

最关键的是:

Plaintext
502 = 0
499 = 0

正常 200 请求已经重新成为绝大多数。

这几乎是一次非常干净的 A/B 验证:

Plaintext
屏蔽前:
大量 Sogou UA
→ PHP-FPM 满载
→ 502

屏蔽后:
Sogou = 0
→ PHP-FPM 恢复
→ 502 = 0

十四、PHP-FPM 队列从 510/511 恢复到 0/511

这也是整个排查过程中最有说服力的指标之一。

故障高峰:

Plaintext
PHP-FPM Socket:

510 / 511

EdgeOne 拦截后:

Plaintext
PHP-FPM Socket:

0 / 511

积压请求彻底清空。

服务器内部访问 WordPress 后台,连续测试 5 次:

Plaintext
HTTP=200  0.110 秒
HTTP=200  0.341 秒
HTTP=200  0.321 秒
HTTP=200  0.469 秒
HTTP=200  0.247 秒

5 次全部成功。

再看实时 CPU:

Plaintext
CPU idle:

8%
90%
97%

最终已经达到:

Plaintext
97% 空闲

运行队列也从之前十几个等待任务,恢复到了:

Plaintext
r = 0

至此,这次生产故障基本可以确认已经恢复。

图7:屏蔽 Sogou 后 PHP-FPM Socket 队列从 510/511 恢复为 0/511,本机后台连续 5 次返回 HTTP 200。
图7:屏蔽 Sogou 后 PHP-FPM Socket 队列从 510/511 恢复为 0/511,本机后台连续 5 次返回 HTTP 200。

十五、这也改变了我对“是否升级 2C4G”的判断

在刚开始看到:

Plaintext
CPU 100%
Load 9+
PHP-FPM 堆积
大量 502

时,我确实很容易得出:

1 核 2G 已经不够用了。

如果没有继续查日志,我可能就会直接升级到 2 核 4G。

但现在结果已经证明:

Plaintext
异常流量停止
→ CPU idle 97%

说明:

正常状态下,这台 1 核 2G 服务器其实还有相当大的 CPU 余量。

因此我暂时不准备因为这次 502 就升级服务器。

2C4G 当然会带来更好的抗峰值能力。

但如果真正的问题是:

Plaintext
异常爬虫
→ 每分钟数百次动态请求

那么升级服务器只是:

Plaintext
从更早被打满
变成晚一点被打满

解决问题的优先级应该是:

Plaintext
先控制异常流量

观察正常业务资源占用

再决定是否真的需要升级

而不是遇到 502 就直接堆硬件。


十六、为什么暂时直接屏蔽 Sogou,而不是做复杂限速

这里其实还有一个取舍。

当前 EdgeOne 的规则:

Plaintext
*Sogou* → Block

意味着:

真正的搜狗爬虫也会被一起拦截。

这显然不是最精细的方案。

更理想的是:

Plaintext
正常、低频 Sogou
→ 放行

异常高频 Sogou
→ 限速或者拦截

但对我来说,目前 Sogou 本身有两个现实问题:

第一,我的网站在 Sogou 中索引量本来就很小。

第二,Sogou 几乎没有给我的博客带来什么有效流量。

而这次带着 Sogou UA 的异常请求,却已经真正导致:

Plaintext
CPU 100%
PHP-FPM 队列 510/511
后台 502

因此现阶段最合理的选择还是:

继续保留 *Sogou* 拦截。

等网站稳定一段时间以后,如果确实还有必要保留搜狗 SEO,再研究 EdgeOne 的速率限制功能,把“一刀切 Block”升级为“超过阈值才拦截”。

但现在没有必要急着做。


十七、EdgeOne 的基础 Bot 管理暂时也解决不了这个问题

我后来还查看了当前个人版 EdgeOne 的 Bot 管理能力。

目前可以看到的主要功能包括:

Plaintext
人机校验页
AI 爬虫处置
图8:EdgeOne 个人版当前显示的基础 Bot 管理功能。
图8:EdgeOne 个人版当前显示的基础 Bot 管理功能。

但并没有看到可以直接:

Plaintext
识别真实 Sogou
→ 放行

伪造 Sogou UA
→ 拦截

这种精细化搜索引擎 Bot 策略。

因此现阶段还是使用:

Plaintext
User-Agent = *Sogou*
→ Block

最简单可靠。


十八、这次故障给我的几个经验

这次最大的收获,并不是“学会屏蔽一个 Sogou User-Agent”,而是重新确认了一套服务器故障排查顺序。

1. 502 不等于服务器配置一定不够

看到:

Plaintext
1C2G
CPU 100%
502

很容易第一时间想到:

升级服务器。

但这次真正的问题是异常流量。

如果不找到流量来源,升级只会掩盖问题。

2. Load、CPU 和 PHP-FPM 队列要结合看

这次真正把问题坐实的三个数据是:

Plaintext
Load ≈ 9
CPU idle = 0
PHP-FPM queue = 510 / 511

这比单独看某一个 CPU 百分比有意义得多。

3. 本机请求非常适合排除 CDN 和公网问题

使用:

Plaintext
127.0.0.1

直接请求 Nginx,可以迅速判断问题到底在:

Plaintext
外部网络 / CDN

还是:

Plaintext
ECS / Nginx / PHP-FPM / WordPress

这次本机一样大量 502,直接把排查范围缩小到了源站内部。

4. CDN 和服务器缓存必须严格区分

清 W3TC / Redis:

Plaintext

清 EdgeOne / Cloudflare。

两层缓存不应该混为一谈。

5. User-Agent 不能证明爬虫身份

看到:

Plaintext
Sogou web spider/4.0

不能自动认为:

这一定是官方 Sogou Spider。

UA 可以随意伪造。

这次至少抽查的多个高频 IP 都无法通过 PTR 反查验证为 Sogou。

所以目前最严谨的称呼还是:

携带 Sogou UA 的异常高频流量。


十九、最终结果

这次故障最终没有:

  • 升级 ECS
  • 修改 pm.max_children
  • 重启 PHP-FPM
  • 清理 CDN 缓存
  • 调整 Redis
  • 调整 RDS
  • 给 Nginx 增加额外规则

真正执行的核心修复其实只有一个:

Plaintext
EdgeOne
→ User-Agent 通配符 *Sogou*
→ Block

然后:

Plaintext
Sogou UA
从 92%+

0

服务器则从:

Plaintext
Load ≈ 9
CPU idle = 0%
PHP-FPM queue = 510 / 511
大量 499 / 502

恢复到:

Plaintext
Load 持续下降
CPU idle 最高 97%
PHP-FPM queue = 0 / 511
后台连续 5 次 HTTP 200
最近请求 502 = 0

整个过程也再次说明:

当服务器突然“性能不够”时,不要第一时间升级配置。

先回答一个问题:

到底是什么流量、什么进程、什么请求,把资源吃掉了?

有时候真正需要的不是更多 CPU,而是在离源站更远的地方,把本来就不应该进入 PHP 的请求挡掉。

这一次,EdgeOne 正好承担了这个角色。

Linux 服务器运维、部署与线上故障排查

如果你的网站或后端服务部署在 Linux 服务器上,遇到访问异常、Nginx 配置问题、MySQL / Redis 异常、Docker 服务不可用、磁盘占满、CPU / 内存过高等问题,可以联系我做一次远程排查。

适合以下场景:
✅ 网站打不开或访问不稳定
✅ Nginx / PHP-FPM 配置异常
✅ MySQL / Redis 性能或连接问题
✅ Docker 服务部署与维护
✅ 服务器迁移与环境配置
✅ CPU / 内存 / 磁盘异常排查

服务内容:
✅ Linux 环境检查
✅ 网站部署与迁移
✅ Nginx / PHP-FPM / MySQL / Redis 排查
✅ Docker 配置与维护
✅ 服务器性能分析
✅ 长期远程运维支持

如需咨询,请联系我,并注明:Linux 运维咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理