Linux load average 很高但 CPU 不高,应该从哪里排查?

先把 load average 和 CPU 使用率分开看

Linux 服务器上看到 load average 很高,很多人第一反应是“CPU 被打满了”。这个判断并不总是对。load average 表示的是一段时间内处于可运行状态和不可中断睡眠状态的任务数量,简单说,它统计的不只是正在抢 CPU 的进程,也包括一些正在等磁盘、等网络文件系统、等内核锁的进程。

Linux 服务器负载与进程状态排查示意图
负载高但 CPU 不高时,要重点确认进程状态、I/O 等待和任务堆积。

所以会出现一种很常见的现象:top 里 load average 已经到十几甚至几十,但 CPU idle 还有不少,业务却明显变慢。这时如果只盯着 CPU 百分比,很容易把问题带偏。正确思路是先确认这台机器有多少 CPU 核心,再看负载超过核心数多少,以及负载高的同时 CPU、内存、磁盘和进程状态分别是什么样。

例如 4 核服务器上 load average 长时间维持在 12,说明排队或等待的任务明显偏多;但如果 CPU 使用率并不高,就要怀疑瓶颈不在计算本身,而是在 I/O、锁等待、进程堆积或外部依赖上。排查时不要急着重启服务,更不要马上加 CPU,先把等待发生在哪里找出来。

先用 uptime 和 nproc 判断压力级别

第一步可以从最简单的命令开始:

uptime
nproc

uptime 会显示 1 分钟、5 分钟、15 分钟三个 load average 数值,nproc 显示 CPU 逻辑核心数。一般来说,如果负载短暂高于核心数,不一定是事故;如果 5 分钟和 15 分钟都明显高于核心数,就说明压力已经持续了一段时间。尤其是 15 分钟负载也很高,通常不是瞬时流量尖峰,而是系统里有任务长期排队。

这里不要机械套用“load 大于核心数就一定异常”。数据库批处理、备份压缩、日志分析、编译任务都可能短时间拉高负载。真正要关注的是:负载高是否影响业务响应、是否伴随磁盘等待、是否有大量同类进程堆积,以及负载曲线是突然抬升还是缓慢爬升。

如果你刚接手一台线上服务器,建议先记录当前时间、核心数、负载三组数值,再继续排查。这样后面看日志、监控和定时任务时,能把故障时间点对齐,避免只看到一个孤立的 top 截图。

top 里重点看进程状态

进入 top 后,不要只看最上面的 CPU 行,还要观察进程状态。Linux 里常见状态包括 R、S、D、Z 等。其中 R 代表可运行或正在运行,D 代表不可中断睡眠,通常和 I/O 等待有关。load average 会把 R 和 D 状态的任务都算进去,所以大量 D 状态进程会把负载推高,即使 CPU 并没有被打满。

top
# 进入 top 后可以按 P 按 CPU 排序,按 M 按内存排序

如果看到很多进程处于 R 状态,并且 CPU user 或 system 很高,问题更像是计算压力、进程数过多或代码死循环。如果看到很多进程处于 D 状态,而 CPU idle 仍然较高,就要重点查磁盘、网络存储、数据库连接、日志写入等等待型问题。

还有一种情况是僵尸进程 Z 很多。少量僵尸进程不一定立刻影响性能,但大量堆积通常说明父进程没有正确回收子进程,可能会进一步拖累服务管理和进程调度。此时需要定位父进程,而不是直接对僵尸进程反复 kill。

用 ps 找出 R 和 D 状态任务

top 适合快速观察,但要定位具体是谁在堆积,ps 更直观。可以按状态筛选当前正在运行或等待 I/O 的进程:

ps -eo pid,ppid,stat,comm,wchan:32,etime,%cpu,%mem --sort=stat | egrep '^[[:space:]]*[0-9]+[[:space:]]+[0-9]+[[:space:]]+[RD]'

这里的 stat 能看到进程状态,wchan 能看到进程大概卡在内核的哪个等待点,etime 能看到进程已经存在多久。如果大量进程都是同一个服务产生的,并且持续时间很长,就要回到这个服务的日志和连接状态里继续查。

如果 D 状态集中在 Web 服务进程,比如 php-fpm、nginx worker 或 Java 应用线程,可能是请求在等待数据库、磁盘、远程接口或网络文件系统。如果 D 状态集中在备份、压缩、rsync、日志切割一类任务,可能是定时任务和业务高峰撞车。排查时要把进程名、父进程、启动时间和故障时间线放在一起看。

对于线上机器,不建议看到 D 状态就强行 kill -9。D 状态进程通常处在不可中断等待里,kill 未必立即生效,粗暴处理还可能扩大影响。更稳妥的做法是先确认等待来源,比如磁盘是否卡住、NFS 是否异常、数据库是否响应慢,再决定是否重启单个服务或切走流量。

iowait 不高也不能完全排除磁盘

很多人会用 iowait 判断磁盘问题,这是对的,但不能只看一个瞬时值。可以先用 vmstat 连续观察:

vmstat 1 10

重点看 r、b、wa 几列。r 表示运行队列,b 表示不可中断睡眠任务数量,wa 表示 CPU 等待 I/O 的比例。如果 b 持续偏高,说明系统里有任务卡在不可中断等待;如果 wa 也高,磁盘或底层存储压力就更明显。

但有些场景下 iowait 不一定特别高,例如进程等待的是网络存储、内核锁、块设备异常恢复,或者大量请求卡在数据库外部依赖上。此时 load 高、CPU 不高、业务慢,仍然可能和 I/O 链路有关。可以结合 iostat、dmesg 和应用日志继续确认:

iostat -xz 1 5
dmesg -T | tail -100
journalctl -p warning..alert --since "30 min ago"

iostat 里如果看到 await、util 长时间偏高,说明设备响应慢;dmesg 里如果有 I/O error、reset、timeout、filesystem remount 等信息,就要把磁盘、云盘、RAID、文件系统健康状态纳入排查范围。

小心定时任务和批处理叠加

load average 突然升高,但 CPU 没打满,还有一个常见原因是定时任务叠加。比如凌晨备份、日志压缩、数据库导出、站点扫描、缓存预热同时开始,单个任务看起来都合理,叠在一起就会让系统队列变长。

可以检查最近执行过的 cron、systemd timer 和业务自己的计划任务:

crontab -l
ls -lah /etc/cron.*
systemctl list-timers --all
journalctl --since "2 hours ago" | grep -iE 'cron|backup|dump|rotate|rsync'

如果负载高峰总是固定在某个时间点出现,大概率和计划任务有关。处理方式不是简单停掉所有任务,而是错峰、限速、拆分批次。比如备份可以避开访问高峰,rsync 可以加带宽限制,日志分析可以分批处理,大文件压缩可以降低优先级。

在业务服务器上,批处理任务最好有明确的资源边界。可以使用 nice、ionice、systemd resource control 或容器资源限制,让后台任务别和线上请求抢同一批资源。这样即使定时任务出问题,也不至于把整台机器拖到不可用。

再看 Web、数据库和连接池

如果高负载发生在网站服务器上,还要检查请求是否堆积。Web 服务、PHP-FPM、数据库连接池、队列消费者都可能因为下游慢而堆出大量等待任务。表现上看,CPU 不一定高,但请求响应时间会拉长,进程数会增加,load average 也会升上去。

可以按服务类型查看进程数量和连接状态:

ps -ef | grep -E 'nginx|php-fpm|mysqld|redis|java' | wc -l
ss -antp | awk '{print $1}' | sort | uniq -c
ss -antp | grep -E ':80|:443|:3306|:6379' | head

如果 TIME-WAIT、ESTAB 或 SYN-RECV 数量异常,要结合访问日志和防火墙判断是正常流量、爬虫、攻击还是应用连接未释放。如果数据库连接很多但查询慢,就要继续看慢查询、锁等待和连接池配置。

网站类业务如果经常因为资源边界不清而排查困难,可以在部署前就把监控、日志和备份策略规划好。选择云服务器时也不要只看 CPU 和内存,磁盘 I/O、线路、备份快照和扩容方式同样关键。像 速维云服务器 这类面向建站和业务部署的产品,在选型时就应结合网站访问地区、并发规模和数据恢复要求一起评估,而不是等负载飙起来再临时补救。

一套实用排查顺序

遇到 load average 很高但 CPU 不高,可以按这个顺序排查:先用 uptime 和 nproc 判断负载相对核心数是否异常;再用 top 看 CPU、内存和进程状态;然后用 ps 抓 R/D 状态任务;接着用 vmstat、iostat、dmesg 判断是否存在 I/O 等待或硬件异常;再检查 cron、备份、日志轮转等计划任务;最后回到 Web、数据库、队列和外部接口日志里定位业务层等待。

这个顺序的好处是先判断系统层,再进入业务层,不会一开始就陷在某个服务配置里。真正的线上故障经常不是单点原因,而是多个因素叠加:磁盘变慢一点、备份任务刚好开始、数据库查询又没有索引,最终表现就是负载升高、CPU 不高、网站整体变慢。

如果短时间内无法完全定位,至少要先做两件事:第一,保留现场信息,包括 top、ps、vmstat、iostat、dmesg、关键服务日志;第二,避免扩大影响,比如暂停非必要批处理、限制异常来源、临时切换流量或扩容只读节点。等业务恢复后,再复盘根因并补监控,否则下一次还会在同一个指标前重新猜一遍。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享