博客 / 詳情

返回

Understanding Linux Load Average

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 的統計來源主要包括兩部分:

  1. 處於就緒隊列(R 狀態)的進程
    表示正在運行或等待 CPU 的進程,反映了對 CPU 的需求。
  2. 處於不可中斷睡眠(D 狀態)的進程
    通常表示在等待磁盤 IO、塊設備或某些內核資源。

因此,Linux 的 load average 實際上反映的是:

系統中“需要 CPU 或無法繼續運行”的進程數量的變化趨勢


指數平滑算法

內核在計算平均負載時,並不是簡單地求平均值,而是使用了 指數加權移動平均(Exponential Moving Average, EMA)

計算公式為:

\[load_{new} = load_{old} \times \alpha + active \times (1 - \alpha) \]

其中:

\[\alpha = e^{-1/n}, \quad n = T / \Delta T \]

  • 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_1EXP_5EXP_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 升高可能意味着:

  1. 大量進程正在消耗 CPU
  2. 大量進程在等待 IO
  3. 大量進程在內核中阻塞(鎖競爭等)

如何進一步排查 Load Average 升高的原因

可以從以下幾個維度進行分析:

  • 每 CPU 利用率
    • mpstat -P ALL 1
  • 進程 / 線程 CPU 使用情況:
    • top
    • pidstat 1
  • 線程調度延遲(run queue latency)
    • /proc/PID/schedstats
    • delaystats
    • perf sched
  • CPU run queue 延遲
    • /proc/schedstat
    • perf sched
    • runqlat(BCC)
  • CPU run queue 長度
    • vmstat 1r
    • runqlen(BCC)

參考資料

  1. https://www.codedump.info/post/20200620-sgfap-loadavg/
  2. https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.