平均負(fù)載與 CPU 使用率,到底有啥區(qū)別?
?大家好,我是樹哥。
在性能優(yōu)化中,我們經(jīng)常會關(guān)注 CPU 平均負(fù)載這個指標(biāo)。但如果讓你來跟我解釋一下什么是平均負(fù)載,你能說得清楚嗎?它跟 CPU 使用率有什么區(qū)別?我想可能很多人都數(shù)不清楚,今天我們就來盤一盤 CPU 平均負(fù)載這個指標(biāo)!

平均負(fù)載與 CPU 使用率,到底有啥區(qū)別?
Linux 進(jìn)程狀態(tài)
要弄明白 CPU 平均負(fù)載,我們還需要從 Linux 進(jìn)程狀態(tài)說起。
在 Linux 源碼的 fs/proc/array.c 文件中,其定義了進(jìn)程的 7 種狀態(tài),如下所示:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
第一種狀態(tài):TASK_RUNNING 可執(zhí)行狀態(tài),縮寫 R。
該狀態(tài)表示進(jìn)程可以在 CPU 上運(yùn)行,即具備運(yùn)行的條件。但同一時刻可能有多個進(jìn)程可以運(yùn)行,但并不代表該進(jìn)程已經(jīng)在運(yùn)行。處于 TASK_RUNNING 的進(jìn)程會被放入 CPU 的可執(zhí)行隊(duì)列中,隨后會被進(jìn)程調(diào)度器分配到其中一個 CPU 上 運(yùn)行。
很多操作系統(tǒng)教科書將 CPU 上執(zhí)行的進(jìn)程定義為 RUNNING 狀態(tài),而將可執(zhí)行但是尚未被調(diào)度執(zhí)行的進(jìn)程定義為 READY 狀態(tài),這兩種狀態(tài)在 Linux 系統(tǒng)下統(tǒng)一為 TASK_RUNNING 狀態(tài)。
第二種狀態(tài):TASK_INTERRUPTIBLE 可中斷的睡眠狀態(tài),縮寫 S。
該狀態(tài)的進(jìn)程表示因?yàn)榈却衬硶r間的發(fā)生而被掛起,例如:等待 socket 連接、等待信號量等等。這些進(jìn)程會被放入對應(yīng)事件的等待隊(duì)列中,當(dāng)這些事件發(fā)生時,對應(yīng)等待隊(duì)列中的一個或多個進(jìn)程將被喚醒。
通過 ps 命令我們可以看到,絕大多數(shù)進(jìn)程都處于 TASK_INTERRUPTIBLE 狀態(tài)。這是因?yàn)橛捎?CPU 只有那么幾個,而進(jìn)程卻動輒幾百上千,因此絕大多數(shù)進(jìn)程在某個時刻都是處于睡眠狀態(tài)的。如果不是絕大多數(shù)進(jìn)程都在睡眠,CPU 是無法響應(yīng)得過來的。
第三種狀態(tài):TASK_UNINTERRUPTIBLE 不可中斷睡眠狀態(tài),縮寫 D。
該狀態(tài)與 TASK_INTERRUPTIBLE 狀態(tài)類似,進(jìn)程處于睡眠狀態(tài),但唯一不同的點(diǎn)是該進(jìn)程是不可中斷的。不可中斷指的并不是 CPU 不響應(yīng)外部硬件的中斷,而是指進(jìn)程不響應(yīng)異步信號。
絕大多數(shù)情況下,進(jìn)程處在睡眠狀態(tài)時,總是應(yīng)該能夠響應(yīng)異步信號的。即你能夠通過 kill -15 pid? 方式傳遞異步信號,程序可以做出響應(yīng)。但有時候你會驚奇地發(fā)現(xiàn),kill -9 竟然殺不死一個正在睡眠的進(jìn)程了,這時候有可能就是該進(jìn)程處于不可中斷睡眠狀態(tài)了!
TASK_UNINTERRUPTIBLE 狀態(tài)存在的意義就在于:內(nèi)核的某些處理流程是不能被打斷的,例如:在進(jìn)程對某些硬件進(jìn)行操作時,如果產(chǎn)生中斷的話會導(dǎo)致進(jìn)程與硬件設(shè)備交互被打斷,使得設(shè)備陷入不可控狀態(tài)。這種情況下的 TASK_UNINTERRUPTIBLE 狀態(tài)總是非常短暫的,通過 ps 命令基本上不可能捕捉到。
第四、五種狀態(tài):TASK_STOPPED 暫停狀態(tài)、TASK_TRACED 狀態(tài),縮寫 T。
當(dāng)我們向進(jìn)程發(fā)送一個 SIGSTOP 信號時,它就會因響應(yīng)該信號而進(jìn)入 TASK_STOPPED 狀態(tài)。除非該進(jìn)程本身處于 TASK_UNINTERRUPTIBLE 狀態(tài)而不響應(yīng)信號)。向進(jìn)程發(fā)送一個 SIGCONT 信號,可以讓其從 TASK_STOPPED 狀態(tài)恢復(fù)到 TASK_RUNNING 狀態(tài)。
第六種狀態(tài):TASK_DEAD - EXIT_ZOMBIE 退出狀態(tài),縮寫 Z。
進(jìn)程退出之后,進(jìn)程所占有的所有資源將被回收,隨后該進(jìn)程就被成為僵尸進(jìn)程(Zombie)。一般情況下是子進(jìn)程先于父進(jìn)程退出,并且父進(jìn)程沒有調(diào)用 wait 或 waitpid 回收子進(jìn)程。此時子進(jìn)程即處于僵尸狀態(tài)。
第七種狀態(tài):TASK_DEAD - EXIT_DEAD 退出狀態(tài),縮寫 X。
進(jìn)程被置于 EXIT_DEAD 退出狀態(tài),這意味著接下來的代碼立即就會將該進(jìn)程徹底釋放。一般情況下 EXIT_DEAD 狀態(tài)是非常短暫的,幾乎不可能通過 ps 命令捕捉到。
看完了 Linux 進(jìn)程的 7 種狀態(tài),是不是有點(diǎn)懵了?其實(shí)你只需要記住 Linux 有這 7 種狀態(tài),其中最重要的是 RUNNING 狀態(tài)、UNINTERRUPTIBLE 狀態(tài)就可以了。
我們總結(jié)一下 Linux 的 7 種進(jìn)程狀態(tài):
- TASK_RUNNING 可執(zhí)行狀態(tài),縮寫 R。
- TASK_INTERRUPTIBLE 可中斷的睡眠狀態(tài),縮寫 S。
- TASK_UNINTERRUPTIBLE 不可中斷睡眠狀態(tài),縮寫 D。
- TASK_STOPPED 暫停狀態(tài)、TASK_TRACED 狀態(tài),縮寫 T。
- TASK_DEAD - EXIT_ZOMBIE 退出狀態(tài),縮寫 Z。
- TASK_DEAD - EXIT_DEAD 退出狀態(tài),縮寫 X。
平均負(fù)載的定義
平均負(fù)載的定義是:單位時間內(nèi),系統(tǒng)中處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù)。 這里的可運(yùn)行狀態(tài)和不可中斷狀態(tài),指的就是上文說到的進(jìn)程狀態(tài)。從平均負(fù)載的定義來看,其與進(jìn)程所處的狀態(tài)有關(guān)系,因此我們后續(xù)分析平均負(fù)載的時候,要以該定義為基礎(chǔ)去分析。
對于有 4 核 CPU 的機(jī)器,如果一共運(yùn)行了 4 個進(jìn)程,那么每個 CPU 都運(yùn)行了 1 個進(jìn)程,此時所有的 CPU 都剛好被完全占用。
而如果只有 2 個進(jìn)程,那么意味著 CPU 有 50% 的空閑。而如果有 8 個進(jìn)程,那么意味著 CPU 超載了,平均負(fù)載達(dá)到了 2,但單位時間內(nèi)單個 CPU 需要運(yùn)行 2 個進(jìn)程。
我們可以通過讀取 /proc/cpuinfo 文件獲取系統(tǒng) CPU 信息,如下所示:
$ grep 'model name' /proc/cpuinfo | wc -l2
當(dāng)平均負(fù)載比 CPU 個數(shù)還多的時候,就表示系統(tǒng)已經(jīng)出現(xiàn)了負(fù)載。一般情況下,負(fù)載不超過 70% 的情況下都是正常的。
很多人都會將 CPU 平均負(fù)載與 CPU 使用率搞混,實(shí)際上它們有一定關(guān)聯(lián),但不是同一個東西。
平均負(fù)載是指單位時間內(nèi),處于可運(yùn)行狀態(tài)和不可中斷的進(jìn)程數(shù)。從其定義可以知道,其不僅包括了正在使用 CPU 的進(jìn)程,還包括等待 CPU 和等待 I/O 的進(jìn)程。而 CPU 使用率指的是正在使用 CPU 的進(jìn)程,由此可見它們兩者是不同的。
如果是 CPU 密集型的進(jìn)程,因?yàn)檫M(jìn)程大量使用 CPU,因此平均負(fù)載會上升,CPU 使用率會上升。但如果是 I/O 密集型進(jìn)程,有很多進(jìn)程在等待 I/O 操作,此時進(jìn)程處于不可中斷狀態(tài),因此平均負(fù)載會升高,但是 CPU 使用率卻不一定很高。
由此可見,平均負(fù)載與 CPU 使用率有一定關(guān)聯(lián),但并沒有絕對的關(guān)系。
如何查看平均負(fù)載?
一般來說,我們可以通過 top? 和 uptime 命令來監(jiān)控服務(wù)器的平均負(fù)載。
在服務(wù)器命令行輸入 top 即可查看到當(dāng)前系統(tǒng)的負(fù)載情況,如下圖所示。

上圖中平均負(fù)載的 3 個數(shù)值分別代表 1 分鐘、5 分鐘、15 分鐘系統(tǒng)的平均負(fù)載情況。通過這三個數(shù)值的變化,我們可以知道系統(tǒng)最近一段時間的壓力變化趨勢。例如:load average: 15.00, 10.75, 3.25 表示過去 1 分鐘負(fù)載為 15,過去 5 分鐘負(fù)載為 10.75,過去 15 分鐘負(fù)載為 3.25,可以看到其平均負(fù)載壓力是越來越大的。
top? 命令輸出的信息非常多,有時候會干擾我們的視野。所以如果你只需要看系統(tǒng)負(fù)載情況,那么你可以用 uptime 命令,如下圖所示。

-w438
uptime 命令只輸出了一行信息,非常簡潔。
如果你需要持續(xù)地查看平均負(fù)載的變化,那么可以用如下命令。該命令會會持續(xù)輸出最新的負(fù)載信息,并高亮變化的部分。
watch -d uptime
-w499
總結(jié)
本文首先介紹了 Linux 進(jìn)程的 7 種狀態(tài),分別是:
- TASK_RUNNING 可執(zhí)行狀態(tài),縮寫 R。
- TASK_INTERRUPTIBLE 可中斷的睡眠狀態(tài),縮寫 S。
- TASK_UNINTERRUPTIBLE 不可中斷睡眠狀態(tài),縮寫 D。
- TASK_STOPPED 暫停狀態(tài)、TASK_TRACED 狀態(tài),縮寫 T。
- TASK_DEAD - EXIT_ZOMBIE 退出狀態(tài),縮寫 Z。
- TASK_DEAD - EXIT_DEAD 退出狀態(tài),縮寫 X。
隨后,我們介紹了平均負(fù)載指標(biāo)的定義,即:單位時間內(nèi),系統(tǒng)中處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù)。
接著,我們將其與 CPU 使用率做了對比,知道兩者的區(qū)別在于:平均負(fù)載不僅包括了正在使用 CPU 的進(jìn)程,還包括等待 CPU 和等待 I/O 的進(jìn)程。而 CPU 使用率指的是正在使用 CPU 的進(jìn)程,由此可見它們兩者是不同的。
最后,我們介紹了查看平均負(fù)載指標(biāo)的 2 個命令,即 top? 和 uptime? 命令。如果需要持續(xù)關(guān)注平均負(fù)載的變化,那么可以使用 watch -d uptime 命令持續(xù)輸出,并高亮變化的部分。
參考資料
從源碼角度分析!進(jìn)程狀態(tài)?理解 Linux 進(jìn)程?看云
(13 條消息) Linux 進(jìn)程狀態(tài)解析 之 R、S、D、T、Z、X (主要有三個狀態(tài))_sdkdlwk 的博客 - CSDN 博客_進(jìn)程 d 狀態(tài)
Linux 進(jìn)程狀態(tài) (ps stat) 詳解 - 火星小編 - 博客園?
























