Linux服务器 load average 很高但 CPU 不高怎么办?从 I/O、D 状态进程到数据库阻塞的排查方法

一、CPU 明明不高,为什么服务器还是“卡”?
在服务器运维现场,我经常遇到一种很典型的情况:
网站打开变慢,SSH 登录也有点卡,uptime 一看:
load average: 18.62, 22.15, 19.87
top
很多人第一反应是:“是不是 CPU 不够了?要不要直接换高配机器?”
但实际上,Linux 服务器 load average 高,不一定代表 CPU 被打满。
它更像是一个“系统排队压力指标”,不只统计正在抢 CPU 的进程,还会把一部分处于 不可中断睡眠状态,也就是 D 状态 的进程算进去。
所以这类问题的关键不是马上升级 CPU,而是先判断:
服务器到底是在等 CPU,还是在等磁盘、网络、数据库、文件系统、内核资源?
这篇文章我就按一次真实服务器排查思路,把“load 高但 CPU 不高”的排查过程讲清楚。
二、先看懂 load average:它不等于 CPU 使用率
Linux 的 load average 通常有三个值:
load average: 8.20, 12.35, 15.67
| 指标 | 含义 |
|---|---|
| 1 分钟 load | 最近 1 分钟系统平均负载 |
| 5 分钟 load | 最近 5 分钟系统平均负载 |
| 15 分钟 load | 最近 15 分钟系统平均负载 |
很多人误以为 load 就是 CPU 使用率,其实不是。
在 Linux 中,load average 主要统计两类进程:
- R 状态进程:正在运行,或者正在等待 CPU 调度。
- D 状态进程:不可中断睡眠,通常在等磁盘 I/O、网络文件系统、块设备、内核资源等。
所以会出现这种情况:
CPU idle 70%
load average 30+
CPU 没有忙死,但系统里有大量进程卡在 I/O、磁盘、文件系统、数据库锁、网络存储或内核等待上。
三、第一步:先判断 load 是否真的异常
不要看到 load 是 8、10、20 就立刻紧张,要结合 CPU 核心数看。
查看 CPU 核心数:
nproc
lscpu
CPU(s): 16
| load 数值 | 判断 |
|---|---|
| load 4 | 对 16 核来说不高 |
| load 16 | 接近满负载,需要关注 |
| load 32 | 压力明显偏高 |
| load 60 | 通常已经有阻塞或排队问题 |
如果是一台 4 核服务器,load 16 就很危险;
但如果是一台 32 核服务器,load 16 可能还没到严重程度。
所以第一句话要记住:
load 要和 CPU 核心数一起看,不能孤立看数字。
四、典型服务器配置场景:不同配置下 load 的意义不一样
以香港服务器业务场景举例,不同硬件配置对 load 的承受能力不同。
| 服务器类型 | 示例配置 | 适合业务 | load 判断重点 |
|---|---|---|---|
| 入门型香港服务器 | 4 核 / 8G / SSD / 100M BGP | 企业官网、小型 WordPress、轻量 API | load 超过 4 就要关注 |
| 中高性能香港服务器 | AMD EPYC 16 核 32 线程 / 64G / NVMe SSD / 100M BGP + 25M CN2 | 外贸站、跨境电商、接口服务 | load 超过 20 才算明显偏高 |
| 数据库型服务器 | AMD EPYC 24 核 48 线程 / 128G / NVMe RAID / 独享带宽 | MySQL、Redis、订单系统 | 更关注 I/O wait、磁盘延迟、锁等待 |
| 大带宽下载 / 图片业务服务器 | 多核 CPU / 64G+ 内存 / NVMe 或 SSD 阵列 / 1G 带宽 | 下载站、图片站、视频分发 | 更关注磁盘吞吐、网卡队列、连接数 |
如果是普通云服务器,CPU 低但 load 高,可能是磁盘性能或虚拟化资源限制。
如果是物理服务器,尤其是香港独立服务器,更多要关注磁盘 I/O、数据库、备份任务、网络文件系统和异常进程。
五、排查思路总览:不要一上来就重启
遇到 load 高但 CPU 不高,我一般按这个顺序排查:
1. 看 CPU 核心数和 load 是否匹配
2. 看 top 里的 wa、id、st
3. 找 R 状态和 D 状态进程
4. 查磁盘 I/O 是否堵塞
5. 查内存和 swap 是否异常
6. 查数据库、Web 服务、PHP-FPM 是否排队
7. 查网络连接和文件系统
8. 查硬件、内核、磁盘错误
9. 最后再决定是优化,还是升级服务器配置
因为如果根因是磁盘 I/O 堵塞,你换更强 CPU 没用;如果根因是数据库锁表,你加带宽也没用。
六、先用 top 判断:CPU 是真空闲,还是卡在 I/O wait?
执行:
top
%Cpu(s): 8.0 us, 3.0 sy, 0.0 ni, 70.0 id, 18.0 wa, 0.0 hi, 1.0 si, 0.0 st
| 字段 | 含义 | 重点判断 |
|---|---|---|
| us | 用户态 CPU 使用率 | 应用程序消耗 CPU |
| sy | 内核态 CPU 使用率 | 系统调用、网络、文件系统开销 |
| id | CPU 空闲率 | id 很高但 load 高,要重点查阻塞 |
| wa | I/O wait | 磁盘或块设备等待 |
| st | steal time | 虚拟化环境中被宿主机抢走 CPU |
如果你看到:
id 70%
wa 25%
CPU 不是瓶颈,磁盘 I/O 或存储层大概率有问题。
如果你看到:
id 80%
wa 0%
st 15%
如果是独立物理服务器,st 一般不会明显偏高。
七、找出 D 状态进程:这是 load 高但 CPU 不高的核心线索
执行:
ps -eo state,pid,ppid,cmd,wchan:32 --sort=state | grep '^D'
D 2314 1208 mysqld io_schedule
D 4412 2211 php-fpm ext4_file_read_iter
D 5580 1 rsync wait_on_page_bit_common
D 6122 1 tar blk_mq_get_tag
常见原因包括:
| D 状态来源 | 可能问题 |
|---|---|
| mysqld | 数据库磁盘 I/O 慢、锁等待、临时表落盘 |
| php-fpm | 读取文件慢、访问数据库慢、NFS 卡顿 |
| rsync / tar | 备份任务压垮磁盘 |
| nginx | 静态文件读取慢、日志写入慢 |
| java / node | 日志、缓存、数据库连接阻塞 |
| mount / nfs | 网络文件系统无响应 |
也可以统计一下 D 状态数量:
ps -eo state | grep -c D
八、检查磁盘 I/O:最常见的根因
安装工具:
apt install sysstat iotop -y
yum install sysstat iotop -y
iostat -xz 1 5
| 字段 | 含义 | 异常表现 |
|---|---|---|
| %util | 磁盘忙碌程度 | 长期接近 100% 说明磁盘打满 |
| await | I/O 平均等待时间 | SSD 超过几十 ms 就要关注 |
| r/s、w/s | 每秒读写次数 | 小文件高并发时会很高 |
| rkB/s、wkB/s | 每秒读写吞吐 | 大文件下载、备份时明显升高 |
| aqu-sz | 队列长度 | 队列越长,等待越严重 |
例如:
Device r/s w/s await %util
sda 5.0 320.0 85.3 99.8
磁盘已经接近满负载,进程大量等待 I/O,load 自然升高。
继续查是谁在读写:
iotop -oPa
pidstat -d 1
mysqld
rsync
tar
gzip
php-fpm
java
nginx
updatedb
backup.sh
logrotate
九、检查内存和 swap:CPU 不高也可能是内存不够
查看内存:
free -h
swapon --show
vmstat 1
si so
si、so 长时间不为 0,说明系统正在频繁使用 swap。例如:
procs -----------memory---------- ---swap--
r b swpd free buff cache si so
1 18 4096M 300M 200M 1.2G 25 40
b 代表阻塞进程数量,si/so 代表 swap in / swap out。这种情况通常说明:
服务器内存不足,进程被迫频繁换页,磁盘 I/O 被拖慢,load 被拉高。
常见于:
- MySQL buffer pool 设置过大。
- PHP-FPM 子进程开太多。
- Java 堆内存配置不合理。
- Redis 没有限制 maxmemory。
- 图片、视频处理任务瞬间吃光内存。
十、检查 Web 服务:是不是请求排队了?
如果服务器跑的是 NGINX + PHP-FPM,可以先看连接数:
ss -s
ss -ant | awk '{print $1}' | sort | uniq -c
ESTAB
SYN-RECV
TIME-WAIT
CLOSE-WAIT
SYN-RECV 很多,可能是攻击、半连接过多或前端防护不足。如果
CLOSE-WAIT 很多,可能是应用没有正确关闭连接。如果
ESTAB 很多,说明业务并发较高,需要结合 NGINX、PHP-FPM、数据库一起看。查看 PHP-FPM 进程:
ps -ylC php-fpm --sort:rss
PHP-FPM 常见优化方向:
pm = dynamic
pm.max_children = 50
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 20
pm.max_requests = 500
比如:
服务器内存:16GB
系统和 MySQL 预留:8GB
可给 PHP-FPM:8GB
单个 PHP-FPM 平均占用:120MB
合理 max_children ≈ 8000 / 120 = 66
十一、检查数据库:很多 load 高其实是 MySQL 卡住了
如果服务器上跑 MySQL,load 高但 CPU 不高,很常见的原因是:
- 慢 SQL。
- 大表无索引。
- 临时表写磁盘。
- 磁盘 I/O 被 binlog、redo log、undo log 拖慢。
- 表锁或行锁等待。
- 备份任务和业务争抢磁盘。
查看 MySQL 当前连接:
mysqladmin processlist
SHOW FULL PROCESSLIST;
SHOW ENGINE INNODB STATUS\G
LATEST DETECTED DEADLOCK
TRANSACTIONS
FILE I/O
ROW OPERATIONS
BUFFER POOL AND MEMORY
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1
这种时候真正的问题不是 Web 服务,而是数据库响应变慢。
十二、检查备份任务:很多服务器是被“自己人”打满的
我在香港服务器上见过很多类似情况:
白天业务正常,晚上 load 突然升高。
一查发现是:
tar -zcf backup.tar.gz /www/wwwroot
mysqldump --all-databases
rsync -avz /data remote:/backup
建议备份时加限制。
例如 rsync 限速:
rsync -avz --bwlimit=20000 /data/ backup@remote:/backup/
ionice 降低 I/O 优先级:
ionice -c2 -n7 tar -zcf backup.tar.gz /data
nice 降低 CPU 优先级:
nice -n 19 ionice -c2 -n7 ./backup.sh
如果是数据库备份,尽量避免在业务高峰直接 mysqldump 大库,可以考虑:
- 从库备份。
- 快照备份。
- 分库分表备份。
- 低峰期增量备份。
- 备份盘和业务盘分离。
十三、检查文件系统和磁盘错误:不要忽略硬件层问题
如果 load 很高、D 状态很多、iowait 高,同时系统日志里有磁盘错误,就要小心硬件问题。
查看内核日志:
dmesg -T | egrep -i "error|fail|reset|timeout|ext4|xfs|nvme|ata|scsi"
journalctl -k -p warning
smartctl -a /dev/sda
smartctl -a /dev/nvme0n1
Reallocated_Sector_Ct
Current_Pending_Sector
Offline_Uncorrectable
Media and Data Integrity Errors
Error Information Log Entries
这种情况不要只重启服务,要尽快备份数据并检查硬件。
十四、容器环境下的特殊情况:CPU 不高但被 cgroup 限制
如果业务跑在 Docker、K8s 或容器环境里,还要查 CPU quota。
容器内看 CPU 可能不高,但实际上已经被限制了。
查看容器资源:
docker stats
cat /sys/fs/cgroup/cpu.stat
nr_throttled 持续增加,说明进程被 CPU quota 限流。这种情况表现可能是:
宿主机 CPU 不高
容器内业务响应慢
load 偏高
应用线程排队
- 提高容器 CPU limit。
- 减少容器内线程数。
- 调整 JVM / PHP-FPM / Node worker 数量。
- 将数据库、缓存、Web 服务拆开部署。
十五、快速定位命令清单:现场直接照着跑
下面这组命令适合现场快速排查:
uptime
nproc
top
ps -eo state,pid,ppid,cmd,wchan:32 --sort=state | grep '^D'
ps -eo state | grep -c D
vmstat 1
iostat -xz 1 5
iotop -oPa
pidstat -d 1
free -h
swapon --show
ss -s
ss -ant | awk '{print $1}' | sort | uniq -c
dmesg -T | egrep -i "error|fail|timeout|reset|nvme|ata|scsi|ext4|xfs"
mysqladmin processlist
十六、不同根因对应的解决方案
1. 磁盘 I/O 打满
表现:
CPU idle 高
load 高
iowait 高
D 状态进程多
iostat %util 接近 100%
- 把 HDD 换成 SSD / NVMe。
- 数据库和网站文件分盘。
- 日志、备份、业务文件分离。
- 备份任务加
ionice和限速。 - MySQL 调整 buffer pool,减少临时表落盘。
- 高并发图片 / 下载业务使用独立存储盘或对象存储。
适合升级方向:
AMD EPYC 多核 CPU
64G / 128G 内存
960GB NVMe PCIe Gen4 SSD
业务盘 + 备份盘分离
表现:
free 可用内存低
swap 使用高
vmstat si/so 持续不为 0
load 高但 CPU 不高
- 限制 PHP-FPM 最大子进程数。
- 调整 MySQL innodb_buffer_pool_size。
- 限制 Redis 最大内存。
- 排查 Java / Node 内存泄漏。
- 增加物理内存。
- 尽量避免业务进程频繁 swap。
配置建议:
普通企业站:16G 内存起步
WordPress + MySQL:32G 更稳
跨境电商 / 订单系统:64G 起步
数据库独立部署:建议 64G / 128G
表现:
Web 进程很多
MySQL CPU 不一定高
请求响应慢
load 持续升高
SHOW PROCESSLIST 有大量 Query / Locked / Sending data
- 开启慢查询日志。
- 补索引。
- 避免大表全表扫描。
- 优化 JOIN 和排序。
- 热点表拆分。
- 数据库和 Web 服务分离。
- 使用 Redis 缓存热点数据。
配置建议:
Web 服务器:16 核 / 32G / NVMe
数据库服务器:24 核 / 64G 或 128G / NVMe RAID
数据库尽量不要和备份、日志、大文件下载混跑
表现:
凌晨 load 高
tar / gzip / rsync / mysqldump 占用 I/O
iowait 高
业务访问变慢
- 备份任务错峰执行。
- 使用
ionice降低 I/O 优先级。 - 使用增量备份。
- 限制 rsync 带宽。
- 业务盘和备份盘分离。
- 大库使用从库或快照备份。
5. 网络文件系统或远程存储卡顿
表现:
D 状态进程很多
wchan 显示 nfs / fuse / wait_on_page
本地 CPU 和磁盘都不高
访问挂载目录很慢
- 检查 NFS、对象存储挂载、远程备份目录。
- 避免业务主路径依赖不稳定远程挂载。
- 设置合理 timeout。
- 重要业务文件放本地 NVMe。
- 远程存储只做备份,不做实时业务目录。
十七、什么时候需要升级服务器配置?
不是所有 load 高都要升级,但出现下面情况时,就要认真考虑换配置。
情况一:磁盘 I/O 长期打满
如果业务高峰期:
iostat %util 长期 90%+
await 持续偏高
D 状态进程持续增加
推荐方向:
AMD EPYC 16 核 32 线程
64G DDR4
960GB NVMe PCIe Gen4 SSD
100M BGP + 25M CN2 直连
WordPress 外贸站
跨境电商独立站
中等访问量 API
企业官网集群节点
如果一台服务器同时跑:
NGINX
PHP-FPM
MySQL
Redis
备份任务
图片处理
日志分析
建议拆分为:
Web 前端服务器
数据库服务器
缓存服务器
备份服务器
AMD EPYC 24 核 48 线程
64G / 128G DDR4
NVMe SSD
独立内网连接
情况三:业务并发明显增长
比如原来每天几千 IP,现在增长到几万 IP;
原来只是企业官网,现在变成跨境电商、接口服务、会员系统。
这时候 load 高可能不是故障,而是服务器配置已经接近上限。
升级建议:
| 业务类型 | 推荐配置 |
|---|---|
| 普通企业站 | 4 核 / 8G / SSD |
| WordPress 外贸站 | 8 核 / 16G / SSD 或 NVMe |
| 跨境电商独立站 | 16 核 / 32G 或 64G / NVMe |
| 数据库业务 | 24 核 / 64G 或 128G / NVMe |
| 下载 / 图片业务 | 多核 CPU / 大内存 / NVMe / 1G 带宽 |
| 高并发 API | 多台 Web + 独立 DB + Redis |
十八、一个真实排查案例:load 40,但 CPU 只有 20%
有一次,一台香港服务器出现访问卡顿。
服务器配置大概是:
CPU:AMD EPYC 16 核 32 线程
内存:64GB DDR4
硬盘:960GB NVMe SSD
带宽:100M BGP,含 25M CN2 直连
系统:Ubuntu 22.04
业务:WordPress + WooCommerce + MySQL
现场看到:
load average: 38.21, 42.16, 36.80
top 里 CPU 并不高:us 12%
sy 5%
id 58%
wa 24%
ps -eo state,pid,cmd,wchan:32 | grep '^D'
php-fpm
mysqld
rsync
iostat -xz 1 5
%util 99%
await 80ms+
凌晨备份脚本没有结束
rsync 正在同步大量图片
同时 mysqldump 还在导出数据库
WooCommerce 后台又在生成报表
处理方式:
- 立即暂停 rsync。
- 停止重复 mysqldump。
- 将备份任务调整到低峰。
- rsync 加
--bwlimit。 - 备份脚本加
ionice。 - MySQL 慢日志开启。
- WooCommerce 报表任务错峰执行。
- 后续将备份目录迁移到独立磁盘。
处理后:
load 从 40+ 降到 5-8
CPU 使用率保持 20%-35%
网站后台恢复正常
load 高不一定是 CPU 不够,很多时候是磁盘、数据库和备份任务在互相抢资源。
十九、最终判断逻辑:一句话总结
遇到 Linux 服务器 load average 很高但 CPU 不高,可以按这个逻辑判断:
CPU 不高 + iowait 高 = 优先查磁盘 I/O
CPU 不高 + D 状态多 = 查阻塞进程和文件系统
CPU 不高 + swap 高 = 查内存不足
CPU 不高 + MySQL 连接堆积 = 查慢 SQL 和锁等待
CPU 不高 + 夜间异常 = 查备份、日志、定时任务
CPU 不高 + 容器环境 = 查 cgroup 限制
CPU 不高 + dmesg 报错 = 查硬盘、RAID、文件系统
真正专业的处理方式是先找出进程在等什么。
二十、load 高不是一个点的问题,而是整台服务器的排队信号
Linux 的 load average 很像服务器的“排队长度”。
CPU 不高但 load 高,往往说明服务器不是算不动,而是某些资源被卡住了。
对于网站、数据库、跨境电商、API 服务来说,真正影响稳定性的通常不是单一 CPU 指标,而是:
CPU 调度
磁盘 I/O
内存和 swap
数据库锁
PHP-FPM 队列
备份任务
文件系统
网络连接
硬件健康
如果 load 长期高于 CPU 核心数,并且伴随网站变慢、SSH 卡顿、数据库响应变慢,就必须按上面的链路系统排查。
服务器优化的核心不是盲目升级,而是先判断瓶颈在哪里。
该优化 SQL 就优化 SQL,该换 NVMe 就换 NVMe,该拆数据库就拆数据库,该升级多核高内存物理服务器时也不要硬撑。
这样处理,才能真正让 Linux 服务器稳定下来