如何正確理解CPU使用率和平均負(fù)載的關(guān)系?看完你就知道了
CPU(Central Processing Unit)是計(jì)算機(jī)系統(tǒng)的運(yùn)算和控制核心,是信息處理、程序運(yùn)行的最終執(zhí)行單元,相當(dāng)于系統(tǒng)的“大腦”。
當(dāng) CPU 過(guò)于繁忙,就像“人腦”并發(fā)處理過(guò)多的事情,會(huì)降低做事的效率,嚴(yán)重時(shí)甚至?xí)?dǎo)致崩潰“宕機(jī)”。因此,理解 CPU 的工作原理,合理控制負(fù)載,是保障系統(tǒng)穩(wěn)定持續(xù)運(yùn)行的重要手段。
CPU 的物理核與邏輯核
一臺(tái)機(jī)器可能包含多塊 CPU 芯片,多個(gè) CPU 之間通過(guò)系統(tǒng)總線通信。
超線程(Hyper-Threading)技術(shù)可以讓一個(gè)物理核在單位時(shí)間內(nèi)同時(shí)處理兩個(gè)線程,變成兩個(gè)邏輯核。但它不會(huì)擁有傳統(tǒng)單核 2 倍的處理能力,也不可能提供完整的并行處理能力。
舉個(gè)例子,假設(shè)一個(gè) CPU 芯片就是一個(gè)班級(jí);它有 2 個(gè)物理核,也就是 2 個(gè)同學(xué),老師讓他們分別擔(dān)任班長(zhǎng)和體育委員;過(guò)了一段時(shí)間,校長(zhǎng)要求每個(gè)班級(jí)還要有學(xué)習(xí)委員和生活委員,理論上還需要 2 位同學(xué),但是這個(gè)班級(jí)只有 2 個(gè)人,最后老師只能讓班長(zhǎng)和體育委員兼任。
這樣一來(lái),對(duì)于不了解的人來(lái)說(shuō),這個(gè)班級(jí)有班長(zhǎng)、體育委員、學(xué)習(xí)委員和生活委員 4 個(gè)職位,應(yīng)該有 4 個(gè)人,每個(gè)職位就是一個(gè)邏輯核;但是,實(shí)際上這個(gè)班級(jí)只有 2 位同學(xué),也就是只有 2 個(gè)物理核,雖然他們可以做 4 份工作,但是不能把他們當(dāng)做 4 個(gè)人。
如何查詢 CPU 信息?
在 Linux 系統(tǒng)下,可以從 /proc/cpuinfo 文件中讀取 CPU 信息,如下圖所示:
查看 CPU 個(gè)數(shù):
- cat /proc/cpuinfo | grep 'physical id' | sort | uniq | wc -l
查看 CPU 物理核數(shù):
- cat /proc/cpuinfo | grep 'cpu cores' | sort | uniq
查看 CPU 邏輯核數(shù):
- cat /proc/cpuinfo | grep 'siblings' | sort | uniq
什么是 CPU 使用率?
CPU 使用率就是 CPU 非空閑態(tài)運(yùn)行的時(shí)間占比,它反映了 CPU 的繁忙程度。比如,單核 CPU 1s 內(nèi)非空閑態(tài)運(yùn)行時(shí)間為 0.8s,那么它的 CPU 使用率就是 80%;雙核 CPU 1s 內(nèi)非空閑態(tài)運(yùn)行時(shí)間分別為 0.4s 和 0.6s,那么,總體 CPU 使用率就是 (0.4s + 0.6s) / (1s * 2) = 50%,其中 2 表示 CPU 核數(shù),多核 CPU 同理。
在 Linux 系統(tǒng)下,使用 top 命令查看 CPU 使用情況,可以得到如下信息:
- Cpu(s): 0.2%us, 0.1%sy, 0.0%ni, 77.5%id, 2.1%wa, 0.0%hi, 0.0%si, 20.0%st
- us(user):表示 CPU 在用戶態(tài)運(yùn)行的時(shí)間百分比,通常用戶態(tài) CPU 高表示有應(yīng)用程序比較繁忙。典型的用戶態(tài)程序包括:數(shù)據(jù)庫(kù)、Web 服務(wù)器等。
- sy(sys):表示 CPU 在內(nèi)核態(tài)運(yùn)行的時(shí)間百分比(不包括中斷),通常內(nèi)核態(tài) CPU 越低越好,否則表示系統(tǒng)存在某些瓶頸。
- ni(nice):表示用 nice 修正進(jìn)程優(yōu)先級(jí)的用戶態(tài)進(jìn)程執(zhí)行的 CPU 時(shí)間。nice 是一個(gè)進(jìn)程優(yōu)先級(jí)的修正值,如果進(jìn)程通過(guò)它修改了優(yōu)先級(jí),則會(huì)單獨(dú)統(tǒng)計(jì) CPU 開(kāi)銷。
- id(idle):表示 CPU 處于空閑態(tài)的時(shí)間占比,此時(shí),CPU 會(huì)執(zhí)行一個(gè)特定的虛擬進(jìn)程,名為 System Idle Process。
- wa(iowait):表示 CPU 在等待 I/O 操作完成所花費(fèi)的時(shí)間,通常該指標(biāo)越低越好,否則表示 I/O 存在瓶頸,可以用 iostat 等命令做進(jìn)一步分析。
- hi(hardirq):表示 CPU 處理硬中斷所花費(fèi)的時(shí)間。硬中斷是由外設(shè)硬件(如鍵盤(pán)控制器、硬件傳感器等)發(fā)出的,需要有中斷控制器參與,特點(diǎn)是快速執(zhí)行。
- si(softirq):表示 CPU 處理軟中斷所花費(fèi)的時(shí)間。軟中斷是由軟件程序(如網(wǎng)絡(luò)收發(fā)、定時(shí)調(diào)度等)發(fā)出的中斷信號(hào),特點(diǎn)是延遲執(zhí)行。
- st(steal):表示 CPU 被其他虛擬機(jī)占用的時(shí)間,僅出現(xiàn)在多虛擬機(jī)場(chǎng)景。如果該指標(biāo)過(guò)高,可以檢查下宿主機(jī)或其他虛擬機(jī)是否異常。
由于 CPU 有多種非空閑態(tài),因此,CPU 使用率計(jì)算公式可以總結(jié)為:CPU 使用率 = (1 - 空閑態(tài)運(yùn)行時(shí)間/總運(yùn)行時(shí)間) * 100%。
根據(jù)經(jīng)驗(yàn)法則, 建議生產(chǎn)系統(tǒng)的 CPU 總使用率不要超過(guò) 70%。
什么是平均負(fù)載?
平均負(fù)載(Load Average)是指單位時(shí)間內(nèi),系統(tǒng)處于 可運(yùn)行狀態(tài)(Running / Runnable) 和 不可中斷態(tài) 的平均進(jìn)程數(shù),也就是 平均活躍進(jìn)程數(shù)。
可運(yùn)行態(tài)進(jìn)程包括正在使用 CPU 或者等待 CPU 的進(jìn)程;不可中斷態(tài)進(jìn)程是指處于內(nèi)核態(tài)關(guān)鍵流程中的進(jìn)程,并且該流程不可被打斷。比如當(dāng)進(jìn)程向磁盤(pán)寫(xiě)數(shù)據(jù)時(shí),如果被打斷,就可能出現(xiàn)磁盤(pán)數(shù)據(jù)與進(jìn)程數(shù)據(jù)不一致。不可中斷態(tài),本質(zhì)上是系統(tǒng)對(duì)進(jìn)程和硬件設(shè)備的一種保護(hù)機(jī)制。
在 Linux 系統(tǒng)下,使用 top 命令查看平均負(fù)載,可以得到如下信息:
- load average: 1.09, 1.12, 1.52
這 3 個(gè)數(shù)字分別表示 1分鐘、5分鐘、15分鐘內(nèi)系統(tǒng)的平均負(fù)載。該值越小,表示系統(tǒng)工作量越少,負(fù)荷越低;反之負(fù)荷越高。
平均負(fù)載為多少更合理?
理想情況下,每個(gè) CPU 應(yīng)該滿負(fù)荷工作,并且沒(méi)有等待進(jìn)程,此時(shí),平均負(fù)載 = CPU 邏輯核數(shù)。
但是,在實(shí)際生產(chǎn)系統(tǒng)中,不建議系統(tǒng)滿負(fù)荷運(yùn)行。通用的經(jīng)驗(yàn)法則是:平均負(fù)載 = 0.7 * CPU 邏輯核數(shù)。
- 當(dāng)平均負(fù)載持續(xù)大于 0.7 * CPU 邏輯核數(shù),就需要開(kāi)始調(diào)查原因,防止系統(tǒng)惡化;
- 當(dāng)平均負(fù)載持續(xù)大于 1.0 * CPU 邏輯核數(shù),必須尋找解決辦法,降低平均負(fù)載;
- 當(dāng)平均負(fù)載持續(xù)大于 5.0 * CPU 邏輯核數(shù),表明系統(tǒng)已出現(xiàn)嚴(yán)重問(wèn)題,長(zhǎng)時(shí)間未響應(yīng),或者接近死機(jī)。
除了關(guān)注平均負(fù)載值本身,我們也應(yīng)關(guān)注平均負(fù)載的變化趨勢(shì),這包含兩層含義。一是 load1、load5、load15 之間的變化趨勢(shì);二是歷史的變化趨勢(shì)。
- 當(dāng) load1、load5、load15 三個(gè)值非常接近,表明短期內(nèi)系統(tǒng)負(fù)載比較平穩(wěn)。
此時(shí),應(yīng)該將其與昨天或上周同時(shí)段的歷史負(fù)載進(jìn)行比對(duì),觀察是否有顯著上升。
- 當(dāng) load1 遠(yuǎn)小于 load5 或 load15 時(shí),表明系統(tǒng)最近 1 分鐘的負(fù)載在降低,而過(guò)去 5 分鐘或 15 分鐘的平均負(fù)載卻很高。
- 當(dāng) load1 遠(yuǎn)大于 load5 或 load15 時(shí),表明系統(tǒng)負(fù)載在急劇升高,如果不是臨時(shí)性抖動(dòng),而是持續(xù)升高,特別是當(dāng) load5 都已超過(guò) 0.7 * CPU 邏輯核數(shù) 時(shí),應(yīng)調(diào)查原因,降低系統(tǒng)負(fù)載。
CPU 使用率與平均負(fù)載的關(guān)系
CPU 使用率是單位時(shí)間內(nèi) CPU 繁忙程度的統(tǒng)計(jì)。而平均負(fù)載不僅包括正在使用 CPU 的進(jìn)程,還包括等待 CPU 或 I/O 的進(jìn)程。因此,兩者不能等同,有兩種常見(jiàn)的場(chǎng)景如下所述:
- CPU 密集型應(yīng)用,大量進(jìn)程在等待或使用 CPU,此時(shí) CPU 使用率與平均負(fù)載呈正相關(guān)狀態(tài)。
- I/O 密集型應(yīng)用,大量進(jìn)程在等待 I/O,此時(shí)平均負(fù)載會(huì)升高,但 CPU 使用率不一定很高。
為了更深入的理解 CPU 使用率與平均負(fù)載的關(guān)系,我們舉一個(gè)例子:假設(shè)現(xiàn)在有一個(gè)電話亭,有 4 個(gè)人在等待打電話,電話亭同一時(shí)刻只能容納 1 個(gè)人打電話,只有拿起電話筒才算是真正使用。
那么 CPU 使用率就是拿起電話筒的時(shí)間占比,它只取決于在電話亭里的人的行為,與平均負(fù)載沒(méi)有非常直接的關(guān)系。而平均負(fù)載是指在電話亭里的人加上排隊(duì)的總?cè)藬?shù),如下圖所示:
性能優(yōu)化實(shí)戰(zhàn)
無(wú)論是 CPU 使用率,還是平均負(fù)載,都只是反映系統(tǒng)健康狀態(tài)的度量指標(biāo),而不是問(wèn)題的根因。
因此,它們的價(jià)值主要體現(xiàn)在兩個(gè)方面:一是綜合反映當(dāng)前系統(tǒng)的健康程度,結(jié)合監(jiān)控告警產(chǎn)品,實(shí)現(xiàn)快速響應(yīng);二是初步定位問(wèn)題方向,縮小排查范圍,降低故障恢復(fù)時(shí)間。比如當(dāng) CPU iowait 高時(shí),應(yīng)優(yōu)先排查磁盤(pán) I/O;當(dāng) CPU steal 高時(shí),就優(yōu)先排查宿主機(jī)狀態(tài)。
CPU 涵蓋的問(wèn)題場(chǎng)景有很多,限于篇幅限制,下面以最常見(jiàn)的用戶態(tài) CPU 使用率高為例,介紹下 Java 應(yīng)用的排查思路,其他場(chǎng)景留待后續(xù)分享,推薦閱讀 《如何迅速分析出系統(tǒng)CPU的瓶頸在哪里?》。
如何排查用戶態(tài) CPU 使用率高?
用戶態(tài) CPU 使用率反映了應(yīng)用程序的繁忙程度,通常與我們自己寫(xiě)的代碼息息相關(guān)。因此,當(dāng)你在做應(yīng)用發(fā)布、配置變更或性能優(yōu)化時(shí),如果想定位消耗 CPU 最多的 Java 代碼,可以遵循如下思路:
1、通過(guò) top 命令找到 CPU 消耗最多的進(jìn)程號(hào);
2、通過(guò) top -Hp 進(jìn)程號(hào) 命令找到 CPU 消耗最多的線程號(hào)(列名仍然為 PID);
3、通過(guò)printf "%xn" 線程號(hào) 命令輸出該線程號(hào)對(duì)應(yīng)的 16 進(jìn)制數(shù)字;
4、通過(guò) jstack 進(jìn)程號(hào) | grep 16進(jìn)制線程號(hào) -A 10 命令找到 CPU 消耗最多的線程方法堆棧。
上述方法是目前業(yè)界最常用的診斷流程,如果是非 Java 應(yīng)用,可以將 jstack 替換為 perf。
然而,上述方法有兩個(gè)顯著缺陷,一是操作流程復(fù)雜,而且往往一次 jstack 還不足以定位根因,需要執(zhí)行多次;二是只能用于診斷在線問(wèn)題,如果問(wèn)題已經(jīng)發(fā)生,無(wú)法復(fù)現(xiàn)的話,往往只能不了了之。
作者信息:
夏明,GitHub ID @StabilityMan,花名涯海,阿里云 ARMS & EagleEye 技術(shù)專家,2016 年加入阿里巴巴,一直從事鏈路追蹤和 APM 監(jiān)控診斷領(lǐng)域的相關(guān)工作。