很多人第一次看到报警里的 "Load Average: 24.5" 会本能地去看 CPU 使用率,然后困惑地发现 CPU 只用了 20%。这两个数字不匹配不是监控系统坏了,而是 Load Average 从一开始就不是 CPU 使用率的同义词。
这篇文章把 Load Average 讲透:它精确的定义是什么、三个数字分别代表什么、怎么判断自己的机器是不是真的"过高"、为什么会出现"负载高但 CPU 很闲"这种看似矛盾的现象、以及遇到高负载时一套从确认到定位再到处理的完整操作序列。
看完之后,你再看到 Load 报警,应该能在三分钟内判断出这是 IO 卡住了、锁等待了、还是真的算力不够,而不是把它当成 CPU 问题去处理。
一、Load Average 到底在数什么
先给精确定义:Load Average 是系统中处于"可运行状态(Running)"和"不可中断状态(Uninterruptible Sleep)"的进程数量的指数移动平均值,按运行队列长度计算。
拆开看有两个关键点。
第一类:可运行状态(R 状态)。 指进程拿到了除 CPU 时间以外的一切资源,正在运行或者正在 CPU 的运行队列里排队等待被调度。这类进程是真正"想干活"的:给它 CPU 它立刻能算。
第二类:不可中断状态(D 状态,Uninterruptible Sleep)。 指进程正在等待某个不能被信号打断的内核操作完成,最典型的就是等待磁盘 IO、网络存储(NFS、iSCSI)返回、或者某些硬件操作。这类进程即使给它 CPU 也干不了活,它在等外部设备。
第二类是绝大多数误解的来源。 正因为 D 状态进程被算进了 Load,所以才会有"CPU 空闲但 Load 很高"的合理场景:一堆进程卡在磁盘读写上,谁都不需要 CPU,但队列长度实打实地排在那儿。
需要注意的是"平均"的算法。内核计算的是指数移动平均(EMA),不是简单的算术平均。它对最近的数据权重更高,也就是说 Load 对突发波动敏感,但衰减需要时间——一阵持续 30 秒的 IO 尖峰,会让 1 分钟 Load 冲上去,并且要过好几分钟才回落到正常水平。这也是为什么瞬时抓一个 Load 数值意义不大,要看它随时间的变化趋势。
还有一点常被忽略:Load 是全局的,不按核数归一化。同样是 Load 8,在一台 96 核的机器上毫无压力,在一台 2 核的机器上就是灾难。所以"多少算高"这个问题必须和 CPU 核数一起回答。
最后,Load 统计的是线程(task)而不是传统意义上的进程。一个多线程进程里每个线程都会各自贡献 Load 计数,所以一个开了 200 个线程的 Java 进程,理论上最多能让 Load 冲到 200。
二、三个数字怎么看:1、5、15 分钟
uptime 输出的最后三个数依次是过去 1 分钟、5 分钟、15 分钟的平均负载:
$ uptime
14:32:10 up 35 days, 2:11, 3 users, load average: 4.12, 6.38, 5.90
这三个数字是趋势指示器,组合起来能判断问题的发生时间和走向:
| 组合形态 | 含义 | 说明 |
|---|---|---|
| 15 高、5 中、1 低 | 问题在缓解 | 曾经很忙,现在正在恢复 |
| 15 低、5 中、1 高 | 问题刚发生或正在恶化 | 要立即处理,趋势在上升 |
| 三个都高且接近 | 持续高负载 | 长期存在的容量问题,不是突发 |
| 三个都很低但有卡顿 | Load 不是有效指标 | 可能是单次请求慢,而非并发堆积 |
最常用的判断是 1 分钟 > 5 分钟说明还在恶化,1 分钟 < 15 分钟说明在恢复。报警通常应该基于 5 分钟或 15 分钟值——用 1 分钟值报警会导致大量瞬时抖动触发的误报,比如每天定时任务跑一下就会触发一次。
另外要知道,Linux 的 Load 计算里包含了内核线程(部分场景),并且 Load 采样精度受内核 HZ 配置影响。这些细节不影响日常判断,但要知道 Load 是一个近似量,不要拿它做精确计算。
机器重启后 Load 会清零重新积累,所以刚重启完的 15 分钟值其实只反映了重启以来的状态,这点在判断"长期基线"时要注意。
三、多高算高:除以逻辑核数
判断标准为:Load 除以逻辑 CPU 核数,得到每个核的平均队列长度。
# 查看逻辑 CPU 核数(含超线程)
nproc
grep -c ^processor /proc/cpuinfo
# 物理核数、每核线程数、是否开启超线程
lscpu | grep -E '^CPU\(s\)|Thread|Core|Socket|Model name'
经验参考(一般性建议,具体要结合业务容忍度):
| Load / 逻辑核数 | 状态解读 | 建议动作 |
|---|---|---|
| < 0.7 | 很空闲,有余量 | 正常 |
| 0.7 ~ 1.0 | 充分利用,接近饱和 | 关注趋势,可接受 |
| 1.0 ~ 3.0 | 开始有排队,延迟上升 | 排查原因,考虑扩容或优化 |
| 3.0 ~ 5.0 | 明显过载 | 立即排查,业务应该有感知 |
| > 5.0 | 严重过载 | 应急预案,限流或扩容 |
这个标准不是铁律。延迟敏感型业务(交易撮合、实时接口)在 Load/核数 超过 0.7 时 P99 就可能开始劣化;批处理业务跑在 Load 是核数 3 倍的状态下也完全正常,因为它不关心单次任务的延迟,只关心总吞吐。所以阈值要按业务类型来定。
判断时还要排除定时任务造成的假象:备份、日志切割、病毒库更新这些任务会在固定时间把 Load 拉高几分钟。发现 Load 规律性波动,先看 crontab 和 systemd timer。
另外,容器环境里要特别小心。在容器里执行 uptime 看到的仍然是宿主机的 Load(因为 Load 是全局内核统计量,不是 namespace 隔离的)。看到容器里 Load 很高时,先确认是不是宿主机上别的服务在忙,而不是自己的容器有问题。
四、查看 Load 的几种方式
uptime # 最常用,一行看全
cat /proc/loadavg # 原始数据,脚本友好
top # 第一行显示 load average
w # 同时显示登录用户
sar -q 1 5 # 需要 sysstat,含 runq-sz 和 plist-sz
/proc/loadavg 的输出值得单独讲,因为它比 uptime 信息更全:
$ cat /proc/loadavg
4.12 6.38 5.90 2/847 39215
字段依次是:1 分钟负载、5 分钟负载、15 分钟负载、当前可运行进程数/总进程数、最近创建的 PID。这里第四个字段 2/847 的含义是"此刻有 2 个任务在运行队列、总共 847 个任务",它不含平均,是瞬时值,适合用来确认"当前这一刻到底排了几个"。第五个字段可以做进程创建速率的粗略推断。
sar -q 额外提供 runq-sz(运行队列长度)和 plist-sz(任务总数)的历史序列,配合 -f /var/log/sa/saXX 可以看历史,这是事后复盘高负载时段最有用的数据源之一。
# 安装 sysstat(含 sar、iostat、pidstat)
sudo dnf install -y sysstat # RHEL、Rocky、CentOS
sudo apt install -y sysstat # Debian、Ubuntu
# 启动采集并查看历史(默认每 10 分钟一次)
sudo systemctl enable --now sysstat
sar -q -f /var/log/sa/sa$(date +%d) # 或 /var/log/sysstat/saXX(Debian 系)
五、高 Load 低 CPU:典型原因与验证
这是最能体现 Load 价值的一类场景,也是最能误导人的一类。现象是:Load 冲到几十甚至上百,但 CPU 的 us/sy/id 都显示很空闲。原因只有一个方向——大量进程卡在 D 状态。
# 关键:看 vmstat 的 r 列和 b 列
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 24 0 823412 10234 4210234 0 0 1240 3200 4120 3210 3 2 85 10 0
这里 r 是可运行进程数(对应 R 状态,b 是不可中断睡眠进程数(对应 D 状态)。上面这个输出里 b=24 而 CPU 有 85% 空闲,几乎可以确定 IO 出了问题。如果反过来 r 很高而 b 接近 0,那就是真的 CPU 算力不够。
常见的 D 状态来源:
| 原因 | 特征 | 验证方式 |
|---|---|---|
| 本地磁盘 IO 打满 | %util 接近 100、await 很高 |
iostat -x 1 |
| NFS / iSCSI 等网络存储故障或慢 | 涉及挂载点的进程全部卡死,df 也可能卡住 |
nfsstat、mount、dmesg |
| 大量进程争抢同一把文件锁 | IO 不高但 D 状态多,多见于老旧应用 | cat /proc/PID/stack、perf |
| 硬件故障(磁盘坏、RAID 卡异常) | dmesg 有大量错误信息 |
dmesg -T、smartctl |
| 内存极度紧张导致换页风暴 | si/so 不为 0,伴随 Load 高 | vmstat 1 |
NFS 挂掉是最典型也最容易确诊的一种。 它的标志性现象是:对挂载点执行任何操作(ls、df、stat)都会卡住不动,Ctrl+C 也杀不掉(因为 D 状态不响应信号),而且 D 状态进程无法被 kill -9 终止——因为 -9 也是信号,而这类进程的状态定义就是"不响应信号"。
确认 D 状态进程的命令:
# 按状态列统计进程
ps -eo stat,pid,comm --no-headers | awk '{print $1}' | sort | uniq -c | sort -rn
# 列出所有 D 状态进程及其正在执行的系统调用(WCHAN)
ps -eo stat,pid,ppid,comm,wchan:30,cmd --no-headers | awk '$1 ~ /D/'
# 查看某进程的内核栈,能看到卡在哪个函数
sudo cat /proc/PID/stack # 需要内核支持
sudo cat /proc/PID/wchan # 更轻量,显示等待点
进程状态字段 STAT 的第一位含义(ps 输出):
| 字符 | 含义 | 是否计入 Load |
|---|---|---|
| R | 运行中或在运行队列 | 是 |
| D | 不可中断睡眠(通常等 IO) | 是 |
| S | 可中断睡眠(等事件、等锁、sleep) | 否 |
| T | 被作业控制信号停止 | 否 |
| Z | 僵尸进程 | 否 |
| I | 空闲内核线程 | 否 |
注意第二位还会出现 s(会话首进程)、<(高优先级)、N(低优先级)、+(前台进程组)、l(多线程)等修饰符,判断状态时只看第一位。
六、从确认到处理的操作序列
下面是一个可以直接照着执行的顺序,目的是快速缩小范围而不是一上来就重启。
第一步:确认 Load 状态与趋势。
uptime
cat /proc/loadavg
nproc # 记下核数,算出 Load/核 比值
第二步:区分是 CPU 问题还是 IO 问题。
vmstat 1 5
# 看 r 与 b 的分布,看 wa 是否高,看 cs 是否异常,看 si/so 是否非 0
top -b -n 1 | head -20
# 看 wa 与 st:wa 高是 IO,st 高是宿主机超卖(虚拟机)
第三步:按方向下钻。
CPU 方向:
pidstat -u 1 5 # 进程级 CPU
top -H -p PID # 看某进程的线程
perf top # 函数级热点(需安装 perf,开销较大,注意限时使用)
IO 方向:
iostat -x 1 5 # 看 %util、await、avgqu-sz
iotop -o # 看哪个进程在真读写(需 root)
pidstat -d 1 5 # 进程级 IO 统计
IO 不高但 D 状态多(锁等待或网络存储)时:
mount | grep -E 'nfs|iscsi|cifs' # 先看有没有网络挂载
nfsstat -m # NFS 挂载参数与统计
sudo dmesg -T | tail -50 # 找硬件错误、超时、OOM
for p in $(ps -eo pid,stat --no-headers | awk '$2 ~ /^D/ {print $1}'); do
echo "== PID $p $(cat /proc/$p/comm 2>/dev/null)"; sudo cat /proc/$p/wchan 2>/dev/null; echo
done
第四步:处理。
处理方式取决于第三步的结论:
- 磁盘 IO 打满:用
iotop找到罪魁进程后,如果是备份任务,用ionice降优先级或改到低峰期;如果是数据库刷盘,调数据库参数;如果是日志疯狂写,改日志级别或加 logrotate。 - NFS 无响应:联系存储侧,必要时硬挂载(hard)只能等待,软挂载(soft)会超时返回错误。应急可以先
umount -f强制卸载(注意可能导致 IO 错误),但这是有风险的操作,可能造成数据不一致,先确认没有正在写入的关键进程。 - 真的算力不够:短期用 cgroup 限制次要进程,长期扩容或优化代码。
- 定时任务导致:调整任务时间分散执行。
# 降低某进程的 IO 优先级(CFQ/BFQ 调度器下有效)
sudo ionice -c2 -n7 -p PID # best-effort,最低优先级
sudo ionice -c3 -p PID # idle,仅当无其他 IO 时才让该进程做 IO
# 临时限制某进程 CPU(cgroup v2,Systemd 环境推荐)
sudo systemctl set-property --runtime 服务名 CPUQuota=50%
# cgroup v1 手动方式(临时)
echo PID > /sys/fs/cgroup/cpu/xxx/tasks
关于重启:重启能解决 D 状态进程无法 kill 的问题,但它同时会抹掉现场,让你事后无法知道真正的原因。顺序应该是:先把 /proc/PID/stack、dmesg、iostat 的输出存下来,再考虑重启。
七、把排查变成监控
Load 报警应该和其他指标联动才有意义。单独一条"Load > 20"的告警,值班的人拿到手也只能从头查。更好的做法是在告警里附带定位信息:
| 告警策略 | 阈值建议 | 说明 |
|---|---|---|
| Load/核数 持续 > 3,5 分钟 | 触发 P2 | 用 5 分钟值避免瞬时抖动误报 |
vmstat 的 b 列持续 > 核数 |
触发 P1 | 直接指向 IO 问题,优先级更高 |
iostat 的 await 超过设备基线 2 倍 |
触发 P2 | 阈值要按 SSD/机械盘分别设定 |
| Load 高且 CPU idle 高 | 单独一条"疑似 IO 卡住"告警 | 组合条件,指向明确 |
同时要把 Load 和 r(运行队列)分开监控。Load 是平均值,会掩盖毛刺;r 是瞬时值,能暴露短时间的排队尖峰。两者配合才完整。
常见问题
Load 很高但系统用着很流畅,需要管吗?
看持续性。如果是批处理任务、编译、数据导入导致的短时间高 Load,而且没有影响到在线业务,可以不管。但如果 Load 长期处于核数的 2 倍以上,说明系统余量不足,任何突发流量都可能把它推到不可用的地步,这时候应该扩容或拆分服务。
D 状态进程 kill -9 杀不掉怎么办?
杀不掉是正常的,D 状态的定义就是不响应信号。它会在等待的 IO 完成后自动退出。能做的是处理根因(恢复存储、修复磁盘),或者如果一直不返回,就只能重启机器。重启前务必保存好 dmesg、iostat、进程栈的输出用于事后分析。
容器里看到 Load 很高,是我的容器有问题吗?
大概率不是。Load 是宿主机的全局指标,容器里看 uptime 和宿主机看到的是同一个值。要判断自己容器的资源占用,应该看容器的 CPU、内存 cgroup 统计,或者用 docker stats、kubectl top pod 这类按容器聚合的工具。
Load 和 CPU 使用率完全对不上,是不是计算器算错了?
恰恰相反,这正是 Load 的价值所在。Load 统计的是"运行中 + 不可中断睡眠"的任务数,CPU 使用率统计的是"CPU 忙的时间占比"。CPU 空闲而 Load 高,说明任务在等 IO;CPU 满负荷而 Load 只有 1,说明只有单个线程在死循环。两者描述的本来就是不同的事情。
该用 1 分钟还是 15 分钟值做告警?
告警用 5 分钟或 15 分钟值。1 分钟值抖动太大,日志切割、临时 crontab 都可能触发误报,长期下来会导致告警疲劳。判断当前是否还在恶化时再看 1 分钟值与 5 分钟值的关系。
总结
- Load Average 是"处于可运行状态(R)和不可中断状态(D)的任务数量"的指数移动平均值,不是 CPU 使用率。D 状态进程(等待磁盘 IO、网络存储、某些锁)计入 Load 但不消耗 CPU,这是"高负载低 CPU"的根本原因。
- 三个数字(1/5/15 分钟)是趋势指示器:1 分钟高于 5 分钟说明正在恶化,低于 15 分钟说明在恢复。告警应使用 5 分钟或 15 分钟值以避免瞬时抖动误报;
cat /proc/loadavg的第四个字段r/total是瞬时队列长度,可用来确认当前排队情况。 - 判断是否过高必须除以逻辑核数(
nproc)。经验值:Load/核数 < 0.7 空闲,1~3 有排队延迟上升,> 5 严重过载。延迟敏感的在线业务阈值要更严格,批处理业务可以更宽松。容器里看到的 Load 是宿主机的值,不能直接归因于自己的容器。 - 排查的第一刀是
vmstat 1看 r 与 b 列:r 高是 CPU 算力不足,b 高且 CPU 空闲是 IO 卡住。随后用iostat -x 1、iotop -o、pidstat -d 1定位 IO 来源;用ps -eo stat,pid,wchan:30,cmd列出 D 状态进程,必要时cat /proc/PID/stack看卡在哪个内核函数。 - NFS/iSCSI 挂掉时最典型的特征是对挂载点的操作(
ls、df)全部卡死且Ctrl+C无效,kill -9也杀不掉。这类问题要恢复存储或修复网络,umount -f强制卸载有数据风险,需谨慎评估。 - 临时止损优先用
ionice降低 IO 优先级、systemctl set-property CPUQuota限制 CPU,而不是直接重启。重启会抹掉现场,之前务必留存dmesg、iostat、进程栈等证据;同时把 Load 与运行队列、await 分开监控,用组合条件告警替代单独阈值告警。
企业QQ咨询




