Back to Forum Re New

[MW] 【MW-Panel 老服务器负载 100% 排查与处理记录】

【MW-Panel 老服务器负载 100% 排查与处理记录】

环境:

硬件 1核 CPU / 约2GB内存 / 60GB SSD

软件  OpenResty + PHP 5.3 + MySQL 5.7

网站:www.ceqmap.com

一、现象

MW 面板显示“负载状态 100%,运行堵塞”。

运行 uptime,严重时:load average: 2.74, 1.80, 1.30


1核服务器负载长期明显超过1,说明任务存在排队。

二、排查

1. 看实时负载: uptime

2.  看进程: top

当时内存、Swap、磁盘 I/O 无明显异常,但 PHP-FPM 进程较多,MySQL持续工作。

3.  看最近访问: tail -n 50 /www/wwwlogs/www.ceqmap.com.log

4.  统计高频 IP: tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk
    ‘{print $1}’ | sort | uniq -c | sort -nr | head -20

5.  统计高频 URL: tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk
    ‘{print $7}’ | sed ’s/?.*//’ | sort | uniq -c | sort -nr | head -20

6.  统计 User-Agent: tail -n 10000 /www/wwwlogs/www.ceqmap.com.log |
    awk -F’“’ ‘{print $6}’ | sort | uniq -c | sort -nr | head -20

7.  只统计返回 200 的 IP: tail -n 10000 /www/wwwlogs/www.ceqmap.com.log
    | awk ‘$9==200 {print $1}’ | sort | uniq -c | sort -nr | head -20


三、原因

大量爬虫集中访问论坛 PHP 动态页面,使 PHP-FPM 和 MySQL负载升高。


主要包括: GPTBot AhrefsBot meta-externalagent Amazonbot,


其中最近10000条日志中 Amazonbot 一度有575条请求。

四、处理

在 www.ceqmap.com 的 OpenResty/Nginx server 配置中加入:

阻止高负载爬虫,避免占用 PHP/MySQL

if ($http_user_agent ~*
“(GPTBot|AhrefsBot|meta-externalagent|Amazonbot)”) { return 403; }

保存配置后验证:

tail -n 1000 /www/wwwlogs/www.ceqmap.com.log | grep -Ei
‘GPTBot|AhrefsBot|meta-externalagent|Amazonbot’ | tail -20

正常应看到: HTTP 403 请求耗时基本 0.000

说明 OpenResty 已在进入 PHP/MySQL 前直接拦截。

五、结果

处理前: load average: 2.74, 1.80, 1.30

处理后

逐步下降: 0.49, 1.24, 1.19 1.23, 0.95, 0.99 最终: 0.32, 0.75,0.90

负载恢复正常。

六、以后再次出现“负载100%”

以下顺序:

1. uptime 看负载

2. top 看CPU、内存、PHP-FPM、MySQL

3. tail 日志看最近请求

4. 统计高频 IP / URL /
User-Agent 5. 确认爬虫后在 Nginx/OpenResty 层直接 403 6. 等几分钟再次
uptime

不要一看到负载100%就立即重装系统、恢复备份、升级 PHP 或更换 VPS。

结论:

服务器本身没有明显故障,主要是爬虫大量访问老论坛动态 PHP页面。通过 OpenResty 在 PHP/MySQL
之前拦截高负载爬虫后,1核服务器负载恢复正常。

备注: 本站老程序需要 PHP 5.3,不能因为负载问题随意升级 PHP。
EQ中文世纪地图集地址:
www.ceqmap.com

详版

太长不看,以后 再出该问题 跳到  十二 , 若做了 snapshot 恢复 跳到 十三


=========================================================

【服务器 PHP 5.3 老站高负载 / 爬虫拥堵处理及恢复记录】

环境:
Debian + MW-Panel(mdserver-web)
OpenResty / Nginx
PHP 5.3
MySQL 5.7
服务器:1 核 / 2GB 内存
网站:www.ceqmap.com

网站日志:
/www/wwwlogs/www.ceqmap.com.log

网站 Nginx 配置:
/www/server/web_conf/nginx/vhost/www.ceqmap.com.conf

OpenResty 主配置:
/www/server/openresty/nginx/conf/nginx.conf

PHP 5.3 Nginx 配置:
/www/server/web_conf/php/conf/enable-php-53.conf


==================================================
一、问题现象
==================================================

MW-Panel 经常出现:

负载状态:100%
CPU 使用率:100%
运行堵塞

SSH 检查曾出现:

load average: 2.39, 3.01, 1.37

服务器只有 1 核,因此 Load 长时间超过 1 后,
比较容易出现明显拥堵。

检查发现:

硬盘空间充足;
内存仍有余量;
Swap 基本没有使用;
I/O Wait 很低。

因此本次问题不是硬盘满、内存耗尽或磁盘 I/O 导致。


==================================================
二、最终找到的主要原因
==================================================

检查网站访问日志:

/www/wwwlogs/www.ceqmap.com.log

发现大量搜索引擎、AI、SEO 爬虫集中访问老论坛的动态 PHP 页面,例如:

/forum/forumdisplay.php
/forum/index.php
/forum/stats.php
/bbs/forumdisplay.php
/fddkp/*.php
/rfdkp/*.php

实际发现过:

GPTBot
AhrefsBot
meta-externalagent
Amazonbot
bingbot

其中 Bingbot 尤其明显。

例如曾发现单个 Bingbot IP 在很短时间内连续请求大量:

/forum/forumdisplay.php

这些请求原来返回:

200

意味着请求真正走完整条链路:

爬虫
↓
OpenResty
↓
PHP 5.3
↓
MySQL

老论坛大量页面需要 PHP + MySQL 动态生成。

因此即使单次请求只有 0.01~0.02 秒,
大量并发、连续抓取仍然会明显增加 1 核服务器负载。


==================================================
三、总体处理思路:两层防护
==================================================

不能只采用“发现一个 Bot,就封一个 Bot”的办法。

因为:

1. Bot 种类会不断变化;
2. 以后还可能出现新的 Bot;
3. 部分机器人可能伪装成普通 Chrome;
4. 仅靠 User-Agent 黑名单不可能全部识别。

因此采用两层保护:

【第一层】
已经确认不需要的高负载 Bot
→ OpenResty 直接返回 403
→ 不进入 PHP/MySQL

【第二层】
其他所有 PHP 动态访问
→ 按 IP 限制访问速度
→ 平均 3 次/秒
→ 允许短时间 burst=10
→ 超出后返回 429
→ 不再继续消耗 PHP/MySQL

特别注意:

Google 不加入第一层黑名单!

本站仍然需要 Google 正常抓取和收录。


==================================================
四、第一层:拦截已知高负载 Bot
==================================================

【目的】

对于已经确定不需要的 Bot,
最省服务器资源的办法不是让 PHP 判断,
而是在 OpenResty/Nginx 层直接结束请求。

这样这些请求根本到不了 PHP 5.3 和 MySQL。


【修改文件】

/www/server/web_conf/nginx/vhost/www.ceqmap.com.conf


【主要拦截对象】

OpenAI:
GPTBot
OAI-SearchBot
ChatGPT-User

SEO:
AhrefsBot
SemrushBot

Meta:
meta-externalagent
meta-externalfetcher
facebookexternalhit
Facebot

Amazon:
Amazonbot

Microsoft:
bingbot
BingPreview

Yahoo:
Slurp

Apple:
Applebot

Yandex:
YandexBot

百度:
Baiduspider

字节:
Bytespider

华为:
PetalBot

Common Crawl:
CCBot


【特别保留】

Googlebot
GoogleOther
Google-InspectionTool
Google-Extended

不加入 403 黑名单。


【核心原理】

例如:

if ($http_user_agent ~* "bingbot") {
    return 403;
}

意思是:

如果 User-Agent 中出现 bingbot,
OpenResty 立即返回 HTTP 403。

不再执行 PHP。


【实际验证】

原来:

Bingbot → 200 → 约 0.01~0.02 秒

修改后:

Bingbot → 403 → 0.000 秒

例如日志连续出现:

bingbot → 403 → 0.000

说明第一层防护已经成功:

Bingbot
↓
OpenResty
↓
403
×
PHP 5.3
×
MySQL


==================================================
五、第二层第一步:建立 PHP 限速区
==================================================

【目的】

第一层只能处理“认识的 Bot”。

为了防止未知 Bot、伪装浏览器的机器人以及单个 IP
疯狂请求 PHP,需要建立一个通用 PHP 限速机制。


【修改文件】

/www/server/openresty/nginx/conf/nginx.conf


在 http {} 中原有:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;

下面增加:

# PHP 动态页面防拥堵限速区
# 按访问者 IP 统计,每个 IP 平均最多 3 个请求/秒
limit_req_zone $binary_remote_addr zone=php_perip:10m rate=3r/s;

# 超出限速后返回 HTTP 429
limit_req_status 429;


【这一步到底做什么?】

limit_req_zone:

建立一个名为:

php_perip

的限速统计区。

$binary_remote_addr:

按照访问者 IP 分别计算。

rate=3r/s:

每个 IP 平均允许:

3 个请求/秒。


【重要】

做到这里以后,还没有真正限制任何网页。

这一步只是:

“建立限速规则”。

下一步才是:

“让 PHP 使用这个规则”。


==================================================
六、第二层第二步:让 PHP 5.3 使用限速规则
==================================================

【修改文件】

/www/server/web_conf/php/conf/enable-php-53.conf


当前配置:

set $PHP_ENV 1;

location ~ [^/]\.php(/|$)
{
    try_files $uri =404;

    # PHP 动态页面防拥堵限速
    limit_req zone=php_perip burst=10 nodelay;

    #fastcgi_pass unix:/tmp/php-cgi-53.sock;
    fastcgi_pass MW-UPSTREAM-PHP53;
    fastcgi_index index.php;
    include fastcgi.conf;
    include /www/server/web_conf/php/pathinfo.conf;
}


【这一行是什么意思?】

limit_req zone=php_perip burst=10 nodelay;


zone=php_perip

使用上一节在 nginx.conf 中建立的限速规则。


burst=10

允许短时间额外突发 10 个请求。

原因:

正常用户可能快速点击页面,
浏览器本身也可能短时间连续发出多个请求。

如果完全死卡在每秒 3 次,
可能误伤正常使用。

因此给正常的短时突发留出余量。


nodelay

在 burst 允许范围内:

立即处理,不故意排队等待。


超过“3r/s + burst=10”能够容纳的范围后:

返回:

HTTP 429 Too Many Requests

并阻止超量请求继续进入 PHP。


==================================================
七、为什么第一层和第二层都要保留
==================================================

第一层:

已知 Bot
↓
403
↓
最快、最省资源

例如 Bingbot 即使疯狂请求,
OpenResty 直接 0.000 秒处理掉。


第二层:

未知 Bot / 普通访问 / 未被黑名单识别的机器人
↓
访问 PHP
↓
按 IP 限速
↓
平均 3r/s
burst=10
↓
正常 → PHP 5.3 → MySQL

过快
↓
429
↓
不让超量请求继续压 PHP/MySQL


所以:

403 = 精确拦截已知 Bot

429 = 给剩余 PHP 流量加保险


==================================================
八、Google 的处理原则
==================================================

Google 不加入 Bot 黑名单。

也就是说:

Googlebot 不会因为第一层规则直接得到 403。

但是 Google 访问 PHP 时仍属于 PHP 动态访问,
因此第二层通用限速仍然存在。

这样做的目的:

既保留 Google 正常收录,
又防止任何单个来源在极短时间内把 PHP 5.3 / MySQL 打满。


==================================================
九、每次修改配置必须执行的步骤
==================================================

任何 Nginx/OpenResty 配置修改后:

【第一步:先检查语法】

/www/server/openresty/nginx/sbin/nginx -t


必须看到:

syntax is ok
test is successful


【这一步的目的】

确认配置没有:

拼写错误
括号错误
指令位置错误
参数错误

如果这里报错:

绝对不要 reload。


【第二步:语法正确以后平滑加载】

/www/server/openresty/nginx/sbin/nginx -s reload


【这一步的目的】

让新配置正式生效。

reload 是平滑加载,
不需要为了修改 Nginx 配置直接重启整个 VPS。


==================================================
十、如何确认 Bot 拦截已经生效
==================================================

例如检查 Bingbot:

tail -n 1000 /www/wwwlogs/www.ceqmap.com.log | grep -ai 'bingbot' | tail -20


正常应该看到:

403

以及:

0.000


例如:

bingbot → 403 → 0.000


说明:

请求到 OpenResty 就结束了,
没有继续进入 PHP/MySQL。


==================================================
十一、如何检查 PHP 限速是否触发
==================================================

查看最近 2000 条日志中的 429:

tail -n 2000 /www/wwwlogs/www.ceqmap.com.log | awk '$9==429' | tail -20


统计最近 10000 条有多少个 429:

tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk '$9==429' | wc -l


如果:

没有输出

或者:

0

并不代表配置失败。

只是说明:

目前没有任何 IP 的 PHP 请求速度超过限制。


==================================================
十二、服务器再次出现 100% 时如何排查
==================================================

不要一看到 MW-Panel 100% 就:

换 IP
重装系统
恢复备份
升级 PHP
购买新服务器

先查原因。


【1. 查看系统负载】

uptime


例如:

load average: 0.20, 0.55, 0.59

对于当前 1 核服务器属于很轻的状态。


【2. 查看谁正在吃 CPU / 内存】

top


重点观察:

mysqld
php-fpm
openresty

以及:

CPU idle
内存
Swap
I/O wait


【3. 查看最近网站访问】

tail -n 50 /www/wwwlogs/www.ceqmap.com.log


【4. 找访问最多的 IP】

tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -20


【5. 找仍然获得 200 的高频 IP】

tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk '$9==200 {print $1}' | sort | uniq -c | sort -nr | head -20


这一步非常重要:

403 已经被挡掉的 Bot 不可怕。

真正值得继续调查的是:

某个 IP 大量请求,
而且仍然获得 200。


【6. 查看某个可疑 IP 到底在访问什么】

grep -a '^IP地址 ' /www/wwwlogs/www.ceqmap.com.log | tail -30


把“IP地址”换成实际地址。


【7. 查看 PHP 限速是否正在发挥作用】

tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk '$9==429' | wc -l


==================================================
十三、Snapshot 恢复后的重新部署流程
==================================================

如果以后再次恢复旧 Snapshot,
不要凭记忆乱改。

按照以下顺序恢复。


第 1 步:

uptime
top

目的:

先确认恢复后的服务器基础状态。


第 2 步:

检查高频 User-Agent:

tail -n 10000 /www/wwwlogs/www.ceqmap.com.log | awk -F'"' '{print $6}' | sort | uniq -c | sort -nr | head -20

目的:

确认是否仍有 Bot 在大量访问。


第 3 步:

恢复网站配置中的 Bot 403 黑名单:

/www/server/web_conf/nginx/vhost/www.ceqmap.com.conf

目的:

第一时间把已知高负载 Bot 挡在 PHP 外面。


第 4 步:

nginx -t

完整命令:

/www/server/openresty/nginx/sbin/nginx -t

确认 OK 后:

/www/server/openresty/nginx/sbin/nginx -s reload


第 5 步:

验证例如 Bingbot 是否:

200 → 403


第 6 步:

修改:

/www/server/openresty/nginx/conf/nginx.conf

恢复:

limit_req_zone $binary_remote_addr zone=php_perip:10m rate=3r/s;
limit_req_status 429;

目的:

建立 PHP 按 IP 限速区。


第 7 步:

修改:

/www/server/web_conf/php/conf/enable-php-53.conf

加入:

limit_req zone=php_perip burst=10 nodelay;

目的:

真正让 PHP 请求应用限速。


第 8 步:

再次:

/www/server/openresty/nginx/sbin/nginx -t


确认:

syntax is ok
test is successful


第 9 步:

正式生效:

/www/server/openresty/nginx/sbin/nginx -s reload


第 10 步:

检查:

tail -n 2000 /www/wwwlogs/www.ceqmap.com.log | awk '$9==429' | tail -20

以及:

uptime


==================================================
十四、本次实际处理结果
==================================================

问题严重时曾出现:

load average: 2.39, 3.01, 1.37


第一次处理后曾降到:

load average: 0.92, 0.88, 0.94


后来恢复 Snapshot 后重新部署:

1. Bot 403 黑名单
2. PHP 3r/s + burst=10 + 429


最终再次检查:

load average: 0.20, 0.55, 0.59


最近 2000 条日志没有出现 429。

这说明:

目前服务器负载很低;

已知 Bingbot 等 Bot 已经被 403 提前拦截;

当前正常访问量还没有达到 PHP 通用限速阈值。


==================================================
十五、最终结论
==================================================

本次高负载的主要原因不是:

VPS 损坏
硬盘空间不足
内存耗尽
Swap 不够
磁盘 I/O 故障

而是:

1 核老服务器
+
PHP 5.3 动态网站
+
大量 Bot 集中抓取 PHP 页面
+
PHP/MySQL 被反复调用

最终采用:

第一层:
已知高负载 Bot → 403

第二层:
所有 PHP → 每 IP 平均 3r/s

正常短时突发:
burst=10

超速:
429

Google:
不加入 Bot 403 黑名单

配置修改原则:
先备份 → 修改 → nginx -t → OK → reload


目前结论:

暂时没有必要因为本次问题:

换 IP
重装系统
恢复网站
升级 PHP
升级双核

继续观察实际负载即可。

如果以后再次出现 100%:

先 uptime
→ 再 top
→ 再查访问日志
→ 找高频 200 IP
→ 查 403 / 429
→ 最后根据证据决定怎么处理。


特别备注:

PHP 5.3 是本站老程序兼容性所需,
不能因为本次负载问题随意升级。

本次处理的核心不是“升级 PHP”,
而是尽可能让无意义的高频请求在进入 PHP 5.3 / MySQL 之前就被 OpenResty 拦截。
EQ中文世纪地图集地址:
www.ceqmap.com
【2026-09-22 服务器处理记录】

简要: 解决 磁盘出现每天异常增长数 GB的问题

一、恢复 Snapshot 后确认 PHP 限速配置

恢复 Snapshot 后检查:

grep -n ‘php_perip’ /www/server/openresty/nginx/conf/nginx.conf
/www/server/web_conf/php/conf/enable-php-53.conf

确认配置仍然存在:

Nginx 主配置: limit_req_zone $binary_remote_addr zone=php_perip:10m
rate=3r/s;

PHP 5.3 配置: limit_req zone=php_perip burst=10 nodelay;

即 PHP 动态页面继续执行: 每 IP 平均 3 次/秒,允许 burst=10,超出返回
429。

二、检查 MySQL Binlog 增长速度

当前活动 Binlog: mysql-bin.000036

第一次检查约为: 9.0M

约 2 小时后: 127M

2 小时增长约 118M,即: 约 59MB/小时 约 1.4GB/天。

三、分析 Binlog 写入来源

分析 mysql-bin.000036,主要来源:

32126 showstorybbs 22801 fddkp 19669 rfdkp 6560 cbdkp 2511 eqmapbbs

继续检查 showstorybbs,发现大量:

DELETE FROM sscdb_sessions … INSERT INTO sscdb_sessions …

说明老论坛在页面访问过程中频繁创建、清理 Session。

很多记录 uid=‘0’,说明其中存在大量匿名访问。

基本流程:

访问 PHP 页面 → 老程序写/清理 Session → MySQL 产生写操作 → Binlog
记录这些操作 → Binlog 持续增长

四、Binlog 保留时间由 7 天改为 1 天

检查原运行参数:

expire_logs_days = 7

先备份 MySQL 配置:

cp /www/server/mysql/etc/my.cnf /www/server/mysql/etc/my.cnf.bak-binlog

然后将:

expire_logs_days=7

修改为:

expire_logs_days=1

检查配置:

grep -n ‘expire_logs_days’ /www/server/mysql/etc/my.cnf

确认:

expire_logs_days=1

五、让当前 MySQL 立即生效

因为只修改 my.cnf 后,当前运行中的 MySQL 仍显示 7 天,因此执行:

/www/server/mysql/bin/mysql -S /www/server/mysql/mysql.sock -u root -p
-e “SET GLOBAL expire_logs_days=1;”

再次检查:

/www/server/mysql/bin/mysql -S /www/server/mysql/mysql.sock -u root -p
-e “SHOW VARIABLES LIKE ‘expire_logs_days’;”

确认当前运行值已经为:

expire_logs_days = 1

现在:

当前运行中的 MySQL:1 天 my.cnf 永久配置:1 天

以后服务器/MySQL 重启后仍保持 1 天。

六、检查现有 Binlog

SHOW BINARY LOGS 显示当前有:

mysql-bin.000030 mysql-bin.000031 mysql-bin.000032 mysql-bin.000033
mysql-bin.000034 mysql-bin.000035 mysql-bin.000036

合计约 800MB。

SHOW MASTER STATUS 确认当前正在写:

mysql-bin.000036

由于磁盘空间充足,没有人工 PURGE,也没有直接删除任何 mysql-bin.* 文件。

注意: 不要使用 rm mysql-bin.* 删除 Binlog。 需要人工清理时应使用 MySQL
的 PURGE BINARY LOGS。

七、当前磁盘状态

执行:

df -h /

结果:

总容量:60G 已用:15G 可用:43G 使用率:26%

目前磁盘空间正常。

八、建立新的 Snapshot

确认:

PHP 限速配置正常 MySQL Binlog 保留时间已改为 1 天 当前 MySQL
运行参数也为 1 天 磁盘状态正常

随后建立新的 Snapshot,作为新的稳定恢复点。

九、后续观察

主要观察:

df -h /

以及:

ls -lh /www/server/mysql/data/mysql-bin.*

确认改为 Binlog 保留 1 天以后,磁盘是否不再出现每天异常增长数 GB的问题。
EQ中文世纪地图集地址:
www.ceqmap.com
Back to Forum