Linux 中的 Load Average
在 Linux 系统中,Load Averages 通常指的是 system load averages,可以通过 uptime 命令查看:
$ uptime
09:41:46 up 60 days, 15:05, 16 users, load average: 17.28, 16.55, 17.00
这三个数值分别表示系统在 过去 1 分钟、5 分钟和 15 分钟 内的平均负载。
除了 uptime,也可以直接读取 /proc/loadavg 文件来获取同样的信息。
Load Average 是如何计算的
Load average 经常被误认为是 CPU 使用率。在某些操作系统中确实如此,但 Linux 的 load average 并不等同于 CPU load。
在 Linux 中,load average 的统计来源主要包括两部分:
- 处于就绪队列(R 状态)的进程
表示正在运行或等待 CPU 的进程,反映了对 CPU 的需求。 - 处于不可中断睡眠(D 状态)的进程
通常表示在等待磁盘 IO、块设备或某些内核资源。
因此,Linux 的 load average 实际上反映的是:
系统中“需要 CPU 或无法继续运行”的进程数量的变化趋势
指数平滑算法
内核在计算平均负载时,并不是简单地求平均值,而是使用了 指数加权移动平均(Exponential Moving Average, EMA)。
计算公式为:
其中:
active:当前采样周期内处于 R/D 状态的进程数ΔT:采样间隔(Linux 中为 5 秒)T:统计窗口时间(1 分钟、5 分钟、15 分钟)
例如:
如果采样间隔为 5 秒,窗口为 60 秒,则 n = 12。
Linux 内核实现
Linux 内核中对应的实现如下(kernel/sched/loadavg.c):
#define FSHIFT 11 /* nr of bits of precision */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
#define LOAD_FREQ (5*HZ+1) /* 5 sec intervals */
#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5 2014 /* 1/exp(5sec/5min) */
#define EXP_15 2037 /* 1/exp(5sec/15min) *//** a1 = a0 * e + a * (1 - e)*/
static inline unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{unsigned long newload;newload = load * exp + active * (FIXED_1 - exp);if (active >= load)newload += FIXED_1 - 1;return newload / FIXED_1;
}
由于内核无法直接使用浮点运算,上述代码通过 定点数(fixed-point) 来模拟浮点计算。
例如:
#define FSHIFT 11
#define FIXED_1 (1<<FSHIFT)
表示用 11 位小数来保存精度。
EXP_1、EXP_5、EXP_15 分别对应 1 分钟、5 分钟和 15 分钟窗口的指数衰减因子。
该计算逻辑由全局定时器周期性触发调用:
https://elixir.bootlin.com/linux/v6.18.2/source/kernel/sched/loadavg.c#L351
Load Average 有什么意义
Load average 非常适合用来观察 系统负载随时间的变化趋势:
- load average 为 0
系统完全空闲 - 1 分钟 > 5 分钟 > 15 分钟
系统负载正在上升 - 1 分钟 < 5 分钟 < 15 分钟
系统负载正在下降 - load average 长期高于 CPU 核心数
可能存在性能瓶颈(但并非绝对)
为什么 Load Average 会升高
根据 Brendan Gregg 对 load average 演进历史的分析,Linux 最初只统计对 CPU 的需求,后来为了反映 磁盘 IO 对系统响应性的影响,引入了对 D 状态进程的统计。
需要注意的是,D 状态并不只来自磁盘 IO,例如:
- 等待块设备 IO
- 获取内核锁(如
rwsem_down_read_failed) - 某些驱动或文件系统操作
因此,load average 升高可能意味着:
- 大量进程正在消耗 CPU
- 大量进程在等待 IO
- 大量进程在内核中阻塞(锁竞争等)
如何进一步排查 Load Average 升高的原因
可以从以下几个维度进行分析:
- 每 CPU 利用率:
mpstat -P ALL 1
- 进程 / 线程 CPU 使用情况:
toppidstat 1
- 线程调度延迟(run queue latency)
/proc/PID/schedstatsdelaystatsperf sched
- CPU run queue 延迟
/proc/schedstatperf schedrunqlat(BCC)
- CPU run queue 长度
vmstat 1的r列runqlen(BCC)
参考资料
- https://www.codedump.info/post/20200620-sgfap-loadavg/
- https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html