服务器负载过高的排查与应对指南

当服务器出现 负载 100%、CPU 占用 100% 的情况时,意味着系统资源已经被完全占满。此时网站和应用可能会极度缓慢甚至无法访问。面对这种情况,很多人第一反应是重启服务器,但这往往治标不治本。本文将带你逐步理解这种问题的成因,并提供一套清晰、实用的排查和解决方案。
一、为什么会出现负载和 CPU 占用 100%
服务器负载和 CPU 占用并不是完全等价的指标:
-
负载(Load Average)
指的是单位时间内等待 CPU 执行的进程数。负载持续高于 CPU 核心数时,就说明 CPU 已经供不应求。 -
CPU 占用
反映的是 CPU 在用户态、系统态、等待 I/O 等方面的使用情况。当接近 100% 时,系统没有闲置 CPU 时间。
常见原因有:
-
数据库查询过慢 —— 大量复杂 SQL 堆积在 MySQL,导致 CPU 飙升。 -
PHP-FPM 子进程爆满 —— 请求处理不过来,进程一直在等待。 -
流量突增或恶意攻击 —— 大量请求涌入,资源被耗尽。 -
磁盘 I/O 拖慢系统 —— CPU 在等待磁盘,表现为高负载高 iowait。 -
后台任务异常 —— 定时脚本、爬虫、挖矿进程等非业务进程占用 CPU。
二、紧急应对措施(1–5 分钟)
当服务器已经满负荷运转时,首要目标是快速止血,防止更多请求压垮系统。
1. 查看实时状态
uptime
top -b -n1 | head -n20
-
uptime
显示系统负载。 -
top
能快速确认哪个进程吃掉了 CPU。
2. 找出最耗资源的进程
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -n20
3. 临时重启高负载服务
如果确认是 PHP 或 MySQL 占用异常,可以先尝试重启服务:
systemctl restart php-fpm
systemctl restart mysql
4. 杀掉异常进程
kill -15 <PID> # 优雅停止
kill -9 <PID> # 强制终止
5. 封禁恶意请求 IP
iptables -A INPUT -s 1.2.3.4 -j DROP
三、快速定位问题(5–30 分钟)
止住“出血”后,接下来要找清楚是谁在消耗资源。
1. CPU 和进程分析
top # 按 P 排序看 CPU 占用
htop # 若已安装,交互更直观
2. 数据库状态
mysql -u root -p -e "SHOW FULL PROCESSLIST\G"
-
找出执行时间长的 SQL。 -
重点关注 State
为Sending data
、Copying to tmp table
的语句。
3. 启用慢查询日志
mysql -u root -p -e "SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;"
日志文件可帮助定位消耗 CPU 的 SQL。
4. PHP-FPM 状态
ps -eo pid,cmd,%cpu,%mem --sort=-%cpu | grep php-fpm | head
-
子进程数过多意味着请求堆积。 -
可开启 slowlog 捕捉执行缓慢的脚本。
5. 磁盘与 I/O 检查
iostat -x 1 3
vmstat 1 5
-
若 %iowait
高,说明是磁盘瓶颈。
6. 网络连接情况
ss -tunp | head
netstat -anp | grep ESTABLISHED | wc -l
-
确认是否遭遇异常连接洪水。
四、针对性解决方案
场景 A:MySQL 占用过高
-
通过 SHOW PROCESSLIST
找到长时间运行的查询:
KILL QUERY <id>;
-
使用 EXPLAIN
分析 SQL 并优化索引。 -
检查是否有缺少索引的 JOIN
或ORDER BY
。 -
增加 innodb_buffer_pool_size
提升缓存能力(需结合内存情况)。
场景 B:PHP-FPM 子进程爆满
-
编辑 www.conf
调整最大子进程数:
pm.max_children = 30
-
开启慢日志:
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.log
-
通过 kill -15 <PID>
优雅结束高 CPU 子进程。
场景 C:突发流量或爬虫
-
在 Nginx 配置中添加请求速率限制:
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req zone=one burst=20 nodelay;
-
启用 CDN 或 WAF 来抵挡异常流量。
场景 D:磁盘 I/O 过载
-
检查是否有大备份或日志写入任务。 -
将定时任务移到低峰时段。 -
考虑升级更快的 SSD 或提升 IOPS。
场景 E:异常进程
-
用 ps aux --sort=-%cpu
找出陌生的高 CPU 进程。 -
如果是挖矿木马,应立即隔离服务器,备份数据并重新部署。
五、降低单进程资源占用
在无法立即优化业务逻辑时,可以通过限制进程资源来避免拖垮整个服务器。
1. 调整进程优先级
renice +10 -p <PID>
2. 限制单进程 CPU 使用率
cpulimit -p <PID> -l 40
3. systemd 服务 CPU 配额
systemctl set-property --runtime php-fpm CPUQuota=70%
六、长期优化建议
1. 数据库优化
-
定期分析慢查询日志。 -
使用 pt-query-digest
工具进行 SQL 聚合分析。 -
增加缓存层(Redis)减少数据库压力。 -
考虑读写分离架构。
2. 应用层优化
-
使用缓存(Nginx FastCGI 缓存、Redis 缓存)。 -
减少不必要的 PHP 动态渲染。 -
避免外部 API 调用阻塞请求。
3. 基础设施扩展
-
使用负载均衡器分担流量。 -
部署多台 Web 服务器。 -
数据库读写分离或主从架构。
4. 监控与告警
-
部署监控系统(Prometheus、Grafana、Zabbix)。 -
配置 CPU、内存、磁盘 I/O、MySQL 连接数的报警阈值。 -
提前发现趋势,避免突然爆发。
5. 安全防护
-
定期扫描定时任务与 rootkit。 -
使用 fail2ban 自动封禁暴力请求 IP。 -
启用云服务商提供的 DDoS 防护。
七、可执行操作清单
-
确认占用: top
/ps
查看最耗资源进程。 -
检查数据库: SHOW FULL PROCESSLIST
找慢查询。 -
管理 PHP:重载 php-fpm,检查慢日志。 -
检查磁盘与网络: iostat
、ss
等工具定位瓶颈。 -
应急措施:必要时维护页、防火墙拦截、杀掉异常进程。 -
后续优化:索引优化、缓存、扩容、监控告警。
八、总结
当服务器负载和 CPU 占用率达到 100% 时,切忌盲目重启。正确的处理顺序是:
-
先止血:重启或限制关键进程,防止进一步恶化。 -
再定位:通过进程、慢查询、日志找到问题根源。 -
针对性解决:优化 SQL、调整 php-fpm、限制流量。 -
长期优化:缓存、扩容、监控、安全防护全面落实。
服务器问题从来不是一蹴而就的。只有把临时处理、深度分析和长期优化结合起来,才能确保系统稳定运行。