Linux Load Average 完全解读
Load Average 不是 CPU 使用率,而是系统中 R 状态(可运行)+ D 状态(不可中断睡眠)进程的指数加权移动平均数。 Load Average 是症状,不是原因。 找到并解决真正的瓶颈才是目的。
内核实现原理
Load Average 由内核 kernel/sched/loadavg.c 中的 calc_global_load() 计算。每隔 5 秒(LOAD_FREQ = 5*HZ + 1),内核采样当前活跃进程数,用指数加权移动平均(EWMA)更新三个时间窗口:
load(t) = load(t-1) × e^(-5/60W) + active_tasks × (1 - e^(-5/60W))
其中 W 取 1、5、15(分钟):
| 窗口 | 衰减因子 | 特点 |
|---|---|---|
| 1 min | e^(-5/60) ≈ 0.9200 | 最敏感,突发可瞬间拉高,消退也快 |
| 5 min | e^(-5/300) ≈ 0.9835 | 中等灵敏度,适合观察短期趋势 |
| 15 min | e^(-5/900) ≈ 0.9945 | 最平滑,反映长期负载基线 |
三个数字组合看趋势:
| 模式 | 含义 | 典型场景 |
|---|---|---|
| 1min > 5min > 15min | 负载上升 | 流量高峰开始、新批处理启动 |
| 1min < 5min < 15min | 负载下降 | 高峰已过、问题进程已处理 |
| 三者接近 | 负载稳定 | 系统稳态运行 |
| 1min >> 15min | 突发负载 | 瞬时进程风暴或 IO 抖动 |
核心概念
定义
三个数字:过去 1 分钟、5 分钟、15 分钟内,处于 Running(R 状态) 和 Uninterruptible Sleep(D 状态) 的平均进程数。
$ uptime
load average: 3.52, 2.85, 2.60
Linux 把 D 状态进程计入 Load Average,这是和 FreeBSD(只统计 R 状态)的关键区别。
与 CPU 使用率的根本区别
| 维度 | Load Average | CPU 使用率 |
|---|---|---|
| 统计对象 | R + D 状态进程数 | CPU 时间片使用比例 |
| 是否包含 IO 等待 | 是(D 状态) | 否(wa% 单独统计) |
| 数值范围 | 0 到无穷大 | 0% 到 100% |
| 典型误导 | IO 等待导致高 Load 但 CPU 空闲 | CPU 低但系统响应慢 |
判断流程:
Load Average 偏高
├─ CPU us% 也高 → CPU 密集型 → perf top 定位热点函数
├─ CPU wa% 高 → IO 密集型 → iostat/iotop 定位
├─ D 状态进程多 → NFS 挂载卡住/内核锁等待
└─ R 状态进程多 → CPU 排队等待
/proc/loadavg 详解
cat /proc/loadavg
# 3.52 2.85 2.60 4/1234 56789
# ───── ───── ───── ─────── ──────
# 1min 5min 15min 运行/总 最后PID
- 第四字段:当前 Running 进程数 / 总进程数(瞬时值,未经平滑)
- 第五字段:最近创建的 PID(快速增长 → 进程疯狂 fork)
判断阈值
负载比公式
负载比 = Load Average / CPU 核数
nproc # 查看 CPU 逻辑核数
lscpu | grep -E "^CPU\(s\)|Thread|Core" # 区分物理核/逻辑核
| 负载比 | 状态 | 说明 |
|---|---|---|
| < 0.7 | 健康 | 充足余量,可承受突发 |
| 0.7 – 1.0 | 正常偏高 | 接近满载,关注趋势 |
| 1.0 – 2.0 | 过载 | 进程排队,响应劣化 |
| > 2.0 | 严重过载 | 大量排队,响应严重变慢 |
| > 5.0 | 危险 | 系统可能半瘫痪 |
超线程的影响
超线程(Hyper-Threading)下 nproc 返回逻辑核数(物理核 × 2),但实际增益仅 15-30%。一台 8 物理核 16 逻辑核的机器,Load 到 12 时负载比 0.75,但实际 CPU 压力已不小。保守建议用物理核数评估。
按业务类型调整
- 延迟敏感服务(API 网关、数据库):负载比 > 0.7 告警
- 离线批处理:负载比 1.5–2.0 可接受
- 历史基线:关键是和基线对比,Prometheus 用
avg_over_time(node_load1[7d])计算 baseline
四维判断矩阵
| 场景 | Load | CPU us% | iowait | 判断 |
|---|---|---|---|---|
| 8核 | 12.0 | 15% | 高 | ⚠️ IO 瓶颈 |
| 8核 | 8.5 | 95% | 低 | ⚠️ CPU 瓶颈 |
| 8核 | 60.0 | 95% | 高 | 🔴 双瓶颈 |
三大根因深度分析
原因一:CPU 密集型(us% 高)
特征: Load 高,us% 占主导,iowait 低。
快速确认:
top -bn1 | head -5
# %Cpu(s): 92.3 us, 3.2 sy, 4.5 id, 0.0 wa → us% 主导
典型场景: 死循环/低效算法、正则回溯(ReDoS)、GC 风暴、加密压缩运算、挖矿木马。
深入工具: perf top -p <PID> 或 perf record -g 生成火焰图。Java → async-profiler,Go → pprof。
原因二:IO 等待(wa% 高)
特征: Load 高,CPU 不高(id% 仍有余量),wa% 明显偏高。
快速确认:
top -bn1 | head -5
# %Cpu(s): 5.1 us, 3.8 sy, 12.3 id, 78.2 wa → wa% 主导
iostat -xz 1 3 # 看 %util 和 await
典型场景: HDD 随机 IOPS 打满、数据库慢查询(全表扫描)、日志写入风暴、NFS 延迟、Swap 抖动。
深入工具: iotop -oP 定位 IO 大户,cat /proc/<pid>/io 查看进程 IO 统计。
原因三:进程争抢(进程数暴增)
特征: Load 高但单个进程 CPU/IO 不多,问题在进程数量。
快速确认:
ps aux | wc -l # 总进程数
ps -eo stat | grep -c "^R" # R 状态进程数
cat /proc/loadavg # 第四字段:运行/总进程
典型场景: fork 炸弹、Nginx worker 数过大、cron 堆积(执行时间超过调度间隔)、连接风暴、K8s 调度异常。
三种原因快速鉴别:
| 指标 | CPU 密集型 | IO 等待型 | 进程争抢型 |
|---|---|---|---|
| Load | 高 | 高 | 高 |
| us% | > 80% | < 20% | 30–60% |
| wa% | < 5% | > 20% | 低–中 |
| R 状态 | 多 | 少 | 非常多 |
| D 状态 | 少 | 多 | 少–中 |
| 磁盘 %util | 低 | > 80% | 低–中 |
| 总进程数 | 正常 | 正常 | 异常偏高 |
排查工具链(从宏观到微观)
第一步:uptime — 确认趋势
$ uptime
10:35:22 up 120 days, 7:42, 3 users, load average: 28.15, 12.06, 5.33
# 28 > 12 > 5 → 负载快速攀升,问题刚发生
同时记下核数:nproc(例:8 核,28/8 = 3.5,严重过载)。
第二步:top / htop — 全局概览
top -d 1
# 按 1 → 展开所有核心,看是个别打满还是全部打满
# 按 P → CPU 排序,按 M → 内存排序
头部 CPU 汇总行各字段:us 用户态 / sy 内核态 / ni nice / id 空闲 / wa IO 等待 / hi 硬中断 / si 软中断 / st 虚拟化偷取。
第三步:vmstat — 系统级快照
vmstat 1 10
关键字段:
r— 运行队列,持续 > CPU 核数 → CPU 瓶颈b— D 状态进程数,持续 > 0 → IO 等待si/so— swap in/out,不为 0 → 内存不足cs— 上下文切换,> 10 万 → 进程切换过于频繁
第四步:pidstat — 进程级定位
pidstat -ud 1 5 # CPU + IO,推荐
pidstat -ut 1 5 # 线程级
pidstat -d 能直接看到每个进程的 kB_rd/s 和 kB_wr/s。
第五步:perf — 代码级定位
perf top -p <PID> # 实时热点函数
perf record -g -p <PID> -- sleep 30 # 录制采样
perf report # 生成报告
perf script | stackcollapse-perf.pl | flamegraph.pl > flamegraph.svg # 火焰图
IO 延迟追踪(bpftrace):
bpftrace -e 'tracepoint:block:block_rq_complete {
@usecs = hist((nsecs - args->io_start_time_ns) / 1000); }'
/proc/stat 与 PSI 深度解读
/proc/stat
$ cat /proc/stat | head -1
cpu 2255841 34093 325672 2748123 89532 0 12345 5678 0 0
# user nice system idle iowait irq softirq steal
两次采样差值计算 CPU 使用率分布。Prometheus node_exporter 就是这样采集的。
PSI(Pressure Stall Information)
Linux 4.20+ 引入,比 Load Average 更精确:
$ cat /proc/pressure/cpu
some avg10=4.52 avg60=2.18 avg300=1.06 total=892341523
# some=至少一个任务阻塞的时间百分比,full=所有任务都阻塞
$ cat /proc/pressure/io
some avg10=12.35 avg60=8.72 avg300=5.41 total=2341567890
$ cat /proc/pressure/memory
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
PSI 能精确区分 CPU 压力和 IO 压力,数值是百分比无需除以核数,比 Load Average 更直观。
D 状态进程排查
Uninterruptible Sleep — 等硬件 IO 完成,kill -9 也无法杀死。
ps aux | awk '$8 ~ /D/ {print}' # 查找 D 状态进程
cat /proc/<pid>/stack # 内核堆栈,知道在等什么
ls -la /proc/<pid>/fd # 打开的文件描述符
大量 D 状态进程 → IO 瓶颈严重,排查磁盘和网络。
排查场景与治本方案
场景一:慢 SQL / 代码刷盘
- 治标: 重启业务或 kill 异常 D 状态进程(K8s 重启 Pod)
- 治本: 慢查询日志 +
iotop抓 IO 大户 → 提交研发优化 / 加缓存
场景二:Swap 导致 IO 激增
- 治标:
free -h确认,vmstat 1 5看 si/so;K8s 环境建议swapoff -a - 治本: 排查内存泄漏(
ps按 %MEM 排序)、增加物理内存
场景三:硬件 IO 瓶颈
iostat -x 1 显示 %util ≈ 100%、await 飙高 → 磁盘达到物理极限。
- 治标: 调整 IO 调度算法(SSD→none, HDD→mq-deadline)
- 治本: 换 NVMe、加内存、读写分离、加 Redis 缓存
场景四:NFS / 网络存储挂死
- 治标: 重启 NFS 客户端或
umount -f强制卸载 - 治本: 检查 NFS Server 和网络链路,换高可用存储方案
参见 linux-server-load-case-study 获取完整实战案例。
容器环境下的 Load Average
核心问题:容器看到的是宿主机 Load
容器内执行 uptime 或 cat /proc/loadavg 返回的是宿主机的值。/proc/loadavg 是全局内核接口,不感知 namespace。
宿主机 96 核,Load 48,运行 50 个容器
容器 A(分配 2 核):看到 Load 48 → 若按 2 核算误判为灾难级
容器 B(分配 4 核):看到 Load 48 → 同样的全局值
同时失真的还有 /proc/cpuinfo(显示宿主机全部核数)和 /proc/stat(宿主机的 CPU 统计)。Java/Node.js 等运行时如果用 Load Average 做自适应调优,在容器内全部失效。
正确做法:cgroup 指标
cgroup v2 CPU 控制器:
cat /sys/fs/cgroup/cpu.max # quota period(微秒)
cat /sys/fs/cgroup/cpu.weight # 权重 1-10000,默认 100
cgroup 级 PSI(比系统级 Load Average 精确得多):
cat /sys/fs/cgroup/cpu.pressure
cat /sys/fs/cgroup/io.pressure
K8s Pod 的 cgroup 路径:
# Guaranteed QoS
/sys/fs/cgroup/kubepods.slice/kubepods-pod<UID>.slice/
# Burstable QoS
/sys/fs/cgroup/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod<UID>.slice/
# BestEffort QoS
/sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod<UID>.slice/
Pod CPU 统计:
cat .../cpu.stat
# usage_usec 1234567890
# nr_throttled 1234 ← >0 说明 CPU 被限流
# throttled_usec 5678901 ← 被限流总时间
LXCFS:让容器看到"正确"的 /proc
LXCFS 通过 FUSE 文件系统,把容器内的 /proc/loadavg、/proc/cpuinfo 等替换成基于 cgroup 的虚拟化版本。
K8s DaemonSet 部署,Pod 挂载:
volumeMounts:
- name: lxcfs-proc-loadavg
mountPath: /proc/loadavg
- name: lxcfs-proc-cpuinfo
mountPath: /proc/cpuinfo
volumes:
- name: lxcfs-proc-loadavg
hostPath:
path: /var/lib/lxcfs/proc/loadavg
局限性: Load 计算是近似值(基于 PSI,非原生 EWMA)、FUSE 有微秒级性能开销、进程挂掉会导致挂载点不可访问、需逐个 Pod 配置。
推荐:直接使用 cgroup 原生指标
在 2026 年技术栈下,更推荐直接用 cAdvisor(集成在 kubelet 中)采集的 cgroup 指标:
container_cpu_usage_seconds_total— 容器 CPU 使用量container_cpu_cfs_throttled_periods_total— CPU 限流次数
比在容器内读 /proc/loadavg 更准确可靠。
监控与告警
物理机/VM:Load 负载比
# Warning:负载比 > 0.7 持续 5 分钟
node_load5 / count without(cpu)(node_cpu_seconds_total{mode="idle"}) > 0.7
# Critical:负载比 > 1.0
node_load5 / count without(cpu)(...) > 1.0
# 突增:1min 是 15min 的 3 倍以上
node_load1 / node_load15 > 3 and node_load1 > 4
容器/K8s:cgroup 指标
# CPU 限流比例 > 25%
rate(container_cpu_cfs_throttled_periods_total[5m])
/ rate(container_cpu_cfs_periods_total[5m]) > 0.25
# CPU 使用率接近 limit > 85%
rate(container_cpu_usage_seconds_total[5m])
/ container_spec_cpu_quota * container_spec_cpu_period > 0.85
告警阈值建议
| 环境 | 指标 | Warning | Critical | 持续时间 |
|---|---|---|---|---|
| 物理机/VM | Load 负载比 | > 0.7 | > 1.0 | 5 min |
| 物理机/VM | Load 突增比 | 1min/15min > 3 | > 5 | 2 min |
| 容器 | CPU throttle 比例 | > 25% | > 50% | 5 min |
| 容器 | CPU 使用率/limit | > 85% | > 95% | 5 min |
| 通用 | PSI cpu some | > 20% | > 50% | 5 min |
Shell 快速监控
#!/bin/bash
THRESHOLD=$(nproc)
LOAD=$(awk '{print $1}' /proc/loadavg)
[ "${LOAD%.*}" -gt "$THRESHOLD" ] && echo "Alert: Load $LOAD > $THRESHOLD cores"
命令速查表
# 查看 Load Average
uptime # 快速查看
cat /proc/loadavg # 详细信息(含进程数和最新 PID)
# CPU 核数
nproc # 逻辑核数
lscpu | grep -E "^CPU\(s\)|Thread|Core" # 详细拓扑
# 系统级排查
top -d 1 # 实时监控(按 1 展开核心)
vmstat 1 10 # 重点看 r/b/wa 列
mpstat -P ALL 1 5 # 每核使用率
# 进程级排查
pidstat -ud 1 5 # CPU + IO(进程级)
pidstat -ut 1 5 # CPU(线程级)
ps -eo stat | grep -c "^D" # D 状态进程计数
# 代码级
perf top -p <PID> # 实时热点函数
perf record -g -p <PID> -- sleep 30 # 录制采样
# IO 排查
iostat -xz 1 3 # 磁盘 IO 统计
iotop -oP # 按进程显示 IO
# PSI 压力
cat /proc/pressure/cpu # CPU 压力
cat /proc/pressure/io # IO 压力
# 容器环境
cat /sys/fs/cgroup/cpu.stat # 容器 CPU 统计
cat /sys/fs/cgroup/cpu.pressure # 容器 CPU 压力(cgroup v2)
关键文件路径
| 路径 | 用途 |
|---|---|
/proc/loadavg |
Load Average + 进程统计 |
/proc/stat |
CPU 时间统计 |
/proc/pressure/cpu |
CPU PSI 指标 |
/proc/pressure/io |
IO PSI 指标 |
/sys/fs/cgroup/cpu.stat |
cgroup CPU 统计 |
/sys/fs/cgroup/cpu.pressure |
cgroup CPU PSI |
/sys/fs/cgroup/cpu.max |
CPU 带宽限制 |
关联页面
| 页面 | 关联点 |
|---|---|
| server-performance-four-dimensions | 服务器五维排查总纲 |
| linux-kernel-tuning-production | IO 调度算法 / sysctl 调优 |
| linux-disk-io-tuning | 磁盘 IO 深入调优 |
| linux-server-load-case-study | 完整排查实战案例 |
| fullstack-performance-troubleshooting | 全栈性能排障第一环 |
| network-troubleshooting-order | 网络 IO 瓶颈配合排查 |
| node-troubleshooting | K8s Node 资源压力排查 |
| linux-hardware-info-and-ops-guide | Linux 硬件信息查询与软件管理命令速查 — CPU/内存/磁盘/网络/主板全覆盖 |
| linux-load-high-cpu-low-troubleshooting | Linux Load 高但 CPU 低的排查思路 — 从现象确认到根因定位的系统化诊断流程(含 vm |
| k8s-resource-limits-configuration | K8s CPU 限流机制 |