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