某個應(yīng)用的CPU使用率居然達到100%,我該怎么辦肥矢?

[TOC]
源自極客時間教程的學(xué)習(xí)記錄:
通過前兩節(jié)對平均負載和 CPU 上下文切換的學(xué)習(xí)端衰,我相信你對 CPU 的性能已經(jīng)有了初步了解叠洗。不過我還是想問一下,你最常用什么指標(biāo)來描述系統(tǒng)的 CPU 性能呢?我想你的答案旅东,可能不是平均負載灭抑,也不是 CPU 上下文切換,而是另一個更直觀的指標(biāo)—— CPU 使用率抵代。

我們前面說過腾节,CPU 使用率是單位時間內(nèi) CPU 使用情況的統(tǒng)計,以百分比的方式展示荤牍。那么案腺,作為最常用也是最熟悉的 CPU 指標(biāo),你能說出 CPU 使用率到底是怎么算出來的嗎康吵?再有劈榨,諸如 top、ps 之類的性能工具展示的 %user晦嵌、%nice同辣、 %system、%iowait 惭载、%steal 等等旱函,你又能弄清楚它們之間的不同嗎?

今天我就帶你了解 CPU 使用率的內(nèi)容描滔,同時棒妨,我也會以我們最常用的反向代理服務(wù)器 Nginx 為例,帶你在一步步操作和分析中深入理解伴挚。

CPU 使用率

在上一期我曾提到靶衍,Linux 作為一個多任務(wù)操作系統(tǒng),將每個 CPU 的時間劃分為很短的時間片茎芋,再通過調(diào)度器輪流分配給各個任務(wù)使用颅眶,因此造成多任務(wù)同時運行的錯覺。

為了維護 CPU 時間田弥,Linux 通過事先定義的節(jié)拍率(內(nèi)核中表示為 HZ)涛酗,觸發(fā)時間中斷,并使用全局變量 Jiffies 記錄了開機以來的節(jié)拍數(shù)偷厦。每發(fā)生一次時間中斷商叹,Jiffies 的值就加 1。

節(jié)拍率 HZ 是內(nèi)核的可配選項只泼,可以設(shè)置為 100剖笙、250、1000 等请唱。不同的系統(tǒng)可能設(shè)置不同數(shù)值过蹂,你可以通過查詢 /boot/config 內(nèi)核選項來查看它的配置值聚至。比如在我的系統(tǒng)中扳躬,節(jié)拍率設(shè)置成了 250,也就是每秒鐘觸發(fā) 250 次時間中斷击胜。

$ grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=250

同時潜的,正因為節(jié)拍率 HZ 是內(nèi)核選項,所以用戶空間程序并不能直接訪問信不。為了方便用戶空間程序抽活,內(nèi)核還提供了一個用戶空間節(jié)拍率 USER_HZ下硕,它總是固定為 100梭姓,也就是 1/100 秒。這樣誉尖,用戶空間程序并不需要關(guān)心內(nèi)核中 HZ 被設(shè)置成了多少,因為它看到的總是固定值 USER_HZ琢感。

Linux 通過 /proc 虛擬文件系統(tǒng)探熔,向用戶空間提供了系統(tǒng)內(nèi)部狀態(tài)的信息,而 /proc/stat 提供的就是系統(tǒng)的 CPU 和任務(wù)統(tǒng)計信息柬甥。比方說,如果你只關(guān)注 CPU 的話喜滨,可以執(zhí)行下面的命令:

# 只保留各個CPU的數(shù)據(jù)
$ cat /proc/stat | grep ^cpu
cpu  280580 7407 286084 172900810 83602 0 583 0 0 0
cpu0 144745 4181 176701 86423902 52076 0 301 0 0 0
cpu1 135834 3226 109383 86476907 31525 0 282 0 0 0

這里的輸出結(jié)果是一個表格虽风。其中辜膝,第一列表示的是 CPU 編號厂抖,如 cpu0忱辅、cpu1 墙懂,而第一行沒有編號的 cpu 损搬,表示的是所有 CPU 的累加柜与。其他列則表示不同場景下 CPU 的累加節(jié)拍數(shù),它的單位是 USER_HZ弄匕,也就是 10 ms(1/100 秒)颅悉,所以這其實就是不同場景下的 CPU 時間粘茄。

當(dāng)然签舞,這里每一列的順序并不需要你背下來柒瓣。你只要記住儒搭,有需要的時候芙贫,查詢 man proc 就可以搂鲫。不過,你要清楚 man proc 文檔里每一列的涵義磺平,它們都是 CPU 使用率相關(guān)的重要指標(biāo)魂仍,你還會在很多其他的性能工具中看到它們。下面擦酌,我來依次解讀一下赊舶。

  • user(通痴龃睿縮寫為 us),代表用戶態(tài) CPU 時間寓调。注意,它不包括下面的 nice 時間,但包括了 guest 時間痛悯。
  • nice(通辰ヅ牛縮寫為 ni),代表低優(yōu)先級用戶態(tài) CPU 時間灸蟆,也就是進程的 nice 值被調(diào)整為 1-19 之間時的 CPU 時間。這里注意亲族,nice 可取值范圍是 -20 到 19炒考,數(shù)值越大,優(yōu)先級反而越低霎迫。
  • system(通痴啵縮寫為 sys),代表內(nèi)核態(tài) CPU 時間知给。
  • idle(通橙恐悖縮寫為 id),代表空閑時間涩赢。注意戈次,它不包括等待 I/O 的時間(iowait)。
  • iowait(通惩舶牵縮寫為 wa)怯邪,代表等待 I/O 的 CPU 時間。
  • irq(通郴ǘ眨縮寫為 hi)悬秉,代表處理硬中斷的 CPU 時間澄步。
  • softirq(通常縮寫為 si)和泌,代表處理軟中斷的 CPU 時間村缸。
  • guest(通常縮寫為 guest)武氓,代表通過虛擬化運行其他操作系統(tǒng)的時間梯皿,也就是運行虛擬機的 CPU 時間。

而我們通常所說的 CPU 使用率聋丝,就是除了空閑時間外的其他時間占總 CPU 時間的百分比索烹,用公式來表示就是:

image.png

根據(jù)這個公式,我們就可以從 /proc/stat 中的數(shù)據(jù)弱睦,很容易地計算出 CPU 使用率百姓。當(dāng)然,也可以用每一個場景的 CPU 時間况木,除以總的 CPU 時間垒拢,計算出每個場景的 CPU 使用率。

不過先不要著急計算火惊,你能說出求类,直接用 /proc/stat 的數(shù)據(jù),算的是什么時間段的 CPU 使用率嗎屹耐?

看到這里尸疆,你應(yīng)該想起來了,這是開機以來的節(jié)拍數(shù)累加值惶岭,所以直接算出來的寿弱,是開機以來的平均 CPU 使用率,一般沒啥參考價值按灶。

事實上症革,為了計算 CPU 使用率,性能工具一般都會取間隔一段時間(比如 3 秒)的兩次值鸯旁,作差后噪矛,再計算出這段時間內(nèi)的平均 CPU 使用率,即

image.png

這個公式铺罢,就是我們用各種性能工具所看到的 CPU 使用率的實際計算方法艇挨。

現(xiàn)在,我們知道了系統(tǒng) CPU 使用率的計算方法韭赘,那進程的呢雷袋?跟系統(tǒng)的指標(biāo)類似,Linux 也給每個進程提供了運行情況的統(tǒng)計信息,也就是 /proc/[pid]/stat楷怒。不過蛋勺,這個文件包含的數(shù)據(jù)就比較豐富了,總共有 52 列的數(shù)據(jù)鸠删。

當(dāng)然抱完,不用擔(dān)心,因為你并不需要掌握每一列的含義刃泡。還是那句話巧娱,需要的時候,查 man proc 就行烘贴。

回過頭來看禁添,是不是說要查看 CPU 使用率,就必須先讀取 /proc/stat 和 /proc/[pid]/stat 這兩個文件桨踪,然后再按照上面的公式計算出來呢老翘?

當(dāng)然不是,各種各樣的性能分析工具已經(jīng)幫我們計算好了锻离。不過要注意的是铺峭,性能分析工具給出的都是間隔一段時間的平均 CPU 使用率,所以要注意間隔時間的設(shè)置汽纠,特別是用多個工具對比分析時卫键,你一定要保證它們用的是相同的間隔時間。

比如虱朵,對比一下 top 和 ps 這兩個工具報告的 CPU 使用率莉炉,默認(rèn)的結(jié)果很可能不一樣,因為 top 默認(rèn)使用 3 秒時間間隔碴犬,而 ps 使用的卻是進程的整個生命周期呢袱。

怎么查看 CPU 使用率

知道了 CPU 使用率的含義后,我們再來看看要怎么查看 CPU 使用率翅敌。說到查看 CPU 使用率的工具,我猜你第一反應(yīng)肯定是 top 和 ps惕蹄。的確蚯涮,top 和 ps 是最常用的性能分析工具:

  • top 顯示了系統(tǒng)總體的 CPU 和內(nèi)存使用情況,以及各個進程的資源使用情況卖陵。
  • ps 則只顯示了每個進程的資源使用情況遭顶。

比如,top 的輸出格式為:


# 默認(rèn)每3秒刷新一次
$ top
top - 11:58:59 up 9 days, 22:47,  1 user,  load average: 0.03, 0.02, 0.00
Tasks: 123 total,   1 running,  72 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8169348 total,  5606884 free,   334640 used,  2227824 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  7497908 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   78088   9288   6696 S   0.0  0.1   0:16.83 systemd
    2 root      20   0       0      0      0 S   0.0  0.0   0:00.05 kthreadd
    4 root       0 -20       0      0      0 I   0.0  0.0   0:00.00 kworker/0:0H
...

這個輸出結(jié)果中泪蔫,第三行 %Cpu 就是系統(tǒng)的 CPU 使用率棒旗,具體每一列的含義上一節(jié)都講過,只是把 CPU 時間變換成了 CPU 使用率,我就不再重復(fù)講了铣揉。不過需要注意饶深,top 默認(rèn)顯示的是所有 CPU 的平均值,這個時候你只需要按下數(shù)字 1 逛拱,就可以切換到每個 CPU 的使用率了敌厘。

繼續(xù)往下看,空白行之后是進程的實時信息朽合,每個進程都有一個 %CPU 列俱两,表示進程的 CPU 使用率。它是用戶態(tài)和內(nèi)核態(tài) CPU 使用率的總和曹步,包括進程用戶空間使用的 CPU宪彩、通過系統(tǒng)調(diào)用執(zhí)行的內(nèi)核空間 CPU 、以及在就緒隊列等待運行的 CPU讲婚。在虛擬化環(huán)境中尿孔,它還包括了運行虛擬機占用的 CPU。

所以磺樱,到這里我們可以發(fā)現(xiàn)纳猫, top 并沒有細分進程的用戶態(tài) CPU 和內(nèi)核態(tài) CPU。那要怎么查看每個進程的詳細情況呢竹捉?你應(yīng)該還記得上一節(jié)用到的 pidstat 吧芜辕,它正是一個專門分析每個進程 CPU 使用情況的工具。

比如块差,下面的 pidstat 命令侵续,就間隔 1 秒展示了進程的 5 組 CPU 使用率,包括:

  • 用戶態(tài) CPU 使用率 (%usr)
  • 內(nèi)核態(tài) CPU 使用率(%system)
  • 運行虛擬機 CPU 使用率(%guest)
  • 等待 CPU 使用率(%wait)
  • 以及總的 CPU 使用率(%CPU)憨闰。

最后的 Average 部分状蜗,還計算了 5 組數(shù)據(jù)的平均值。


# 每隔1秒輸出一組數(shù)據(jù)鹉动,共輸出5組
$ pidstat 1 5
15:56:02      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
15:56:03        0     15006    0.00    0.99    0.00    0.00    0.99     1  dockerd

...

Average:      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
Average:        0     15006    0.00    0.99    0.00    0.00    0.99     -  dockerd

CPU 使用率過高怎么辦轧坎?

通過 top、ps泽示、pidstat 等工具缸血,你能夠輕松找到 CPU 使用率較高(比如 100% )的進程。接下來械筛,你可能又想知道捎泻,占用 CPU 的到底是代碼里的哪個函數(shù)呢?找到它埋哟,你才能更高效笆豁、更針對性地進行優(yōu)化。

那么哪種工具適合在第一時間分析進程的 CPU 問題呢?我的推薦是 perf闯狱。perf 是 Linux 2.6.31 以后內(nèi)置的性能分析工具煞赢。它以性能事件采樣為基礎(chǔ),不僅可以分析系統(tǒng)的各種事件和內(nèi)核性能扩氢,還可以用來分析指定應(yīng)用程序的性能問題耕驰。

使用 perf 分析 CPU 性能問題,我來說兩種最常見录豺、也是我最喜歡的用法朦肘。

第一種常見用法是 perf top,類似于 top双饥,它能夠?qū)崟r顯示占用 CPU 時鐘最多的函數(shù)或者指令媒抠,因此可以用來查找熱點函數(shù),使用界面如下所示:


$ perf top
Samples: 833  of event 'cpu-clock', Event count (approx.): 97742399
Overhead  Shared Object       Symbol
   7.28%  perf                [.] 0x00000000001f78a4
   4.72%  [kernel]            [k] vsnprintf
   4.32%  [kernel]            [k] module_get_kallsym
   3.65%  [kernel]            [k] _raw_spin_unlock_irqrestore
...

輸出結(jié)果中咏花,第一行包含三個數(shù)據(jù)趴生,分別是采樣數(shù)(Samples)、事件類型(event)和事件總數(shù)量(Event count)昏翰。比如這個例子中苍匆,perf 總共采集了 833 個 CPU 時鐘事件,而總事件數(shù)則為 97742399棚菊。

另外浸踩,采樣數(shù)需要我們特別注意。如果采樣數(shù)過少(比如只有十幾個)统求,那下面的排序和百分比就沒什么實際參考價值了检碗。

再往下看是一個表格式樣的數(shù)據(jù),每一行包含四列码邻,分別是:

  • 第一列 Overhead 折剃,是該符號的性能事件在所有采樣中的比例,用百分比來表示
  • 第二列 Shared 像屋,是該函數(shù)或指令所在的動態(tài)共享對象(Dynamic Shared Object)怕犁,如內(nèi)核、進程名己莺、動態(tài)鏈接庫名奏甫、內(nèi)核模塊名
  • 第三列 Object ,是動態(tài)共享對象的類型 比如 [.] 表示用戶空間的可執(zhí)行程序篇恒、或者動態(tài)鏈接庫,而 [k] 則表示內(nèi)核空間
  • 最后一列 Symbol 是符號名凶杖,也就是函數(shù)名當(dāng)函數(shù)名未知時胁艰,用十六進制的地址來表示

還是以上面的輸出為例,我們可以看到,占用 CPU 時鐘最多的是 perf 工具自身腾么,不過它的比例也只有 7.28%奈梳,說明系統(tǒng)并沒有 CPU 性能問題。 perf top 的使用你應(yīng)該很清楚了吧解虱。

接著再來看第二種常見用法攘须,也就是 perf record 和 perf report。 perf top 雖然實時展示了系統(tǒng)的性能信息殴泰,但它的缺點是并不保存數(shù)據(jù)于宙,也就無法用于離線或者后續(xù)的分析。而 perf record 則提供了保存數(shù)據(jù)的功能悍汛,保存后的數(shù)據(jù)捞魁,需要你用 perf report 解析展示。


$ perf record # 按Ctrl+C終止采樣
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]

$ perf report # 展示類似于perf top的報告

在實際使用中离咐,我們還經(jīng)常為 perf top 和 perf record 加上 -g 參數(shù)谱俭,開啟調(diào)用關(guān)系的采樣,方便我們根據(jù)調(diào)用鏈來分析性能問題宵蛀。

小結(jié)

CPU 使用率是最直觀和最常用的系統(tǒng)性能指標(biāo)昆著,更是我們在排查性能問題時,通常會關(guān)注的第一個指標(biāo)术陶。所以我們更要熟悉它的含義凑懂,尤其要弄清楚用戶(%user)、Nice(%nice)瞳别、系統(tǒng)(%system) 征候、等待 I/O(%iowait) 、中斷(%irq)以及軟中斷(%softirq)這幾種不同 CPU 的使用率祟敛。比如說:

  1. 用戶 CPU 和 Nice CPU 高疤坝,說明用戶態(tài)進程占用了較多的 CPU,所以應(yīng)該著重排查進程的性能問題馆铁。
  2. 系統(tǒng) CPU 高跑揉,說明內(nèi)核態(tài)占用了較多的 CPU,所以應(yīng)該著重排查內(nèi)核線程或者系統(tǒng)調(diào)用的性能問題埠巨。
  3. I/O 等待 CPU 高历谍,說明等待 I/O 的時間比較長,所以應(yīng)該著重排查系統(tǒng)存儲是不是出現(xiàn)了 I/O 問題辣垒。
  4. 軟中斷和硬中斷高望侈,說明軟中斷或硬中斷的處理程序占用了較多的 CPU,所以應(yīng)該著重排查內(nèi)核中的中斷服務(wù)程序勋桶。

碰到 CPU 使用率升高的問題脱衙,你可以借助 top侥猬、pidstat 等工具,確認(rèn)引發(fā) CPU 性能問題的來源捐韩;再使用 perf 等工具退唠,排查出引起性能問題的具體函數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荤胁,一起剝皮案震驚了整個濱河市瞧预,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仅政,老刑警劉巖垢油,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異已旧,居然都是意外死亡秸苗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門运褪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惊楼,“玉大人,你說我怎么就攤上這事秸讹√戳” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵璃诀,是天一觀的道長弧可。 經(jīng)常有香客問我,道長劣欢,這世上最難降的妖魔是什么棕诵? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮凿将,結(jié)果婚禮上校套,老公的妹妹穿的比我還像新娘。我一直安慰自己牧抵,他們只是感情好笛匙,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著犀变,像睡著了一般妹孙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上获枝,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天蠢正,我揣著相機與錄音,去河邊找鬼省店。 笑死嚣崭,一個胖子當(dāng)著我的面吹牛蜘拉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播有鹿,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谎脯!你這毒婦竟也來了葱跋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤源梭,失蹤者是張志新(化名)和其女友劉穎娱俺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體废麻,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡荠卷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烛愧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片油宜。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖怜姿,靈堂內(nèi)的尸體忽然破棺而出慎冤,到底是詐尸還是另有隱情,我是刑警寧澤沧卢,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布蚁堤,位于F島的核電站,受9級特大地震影響但狭,放射性物質(zhì)發(fā)生泄漏披诗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一立磁、第九天 我趴在偏房一處隱蔽的房頂上張望呈队。 院中可真熱鬧,春花似錦息罗、人聲如沸掂咒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绍刮。三九已至,卻和暖如春挨摸,著一層夾襖步出監(jiān)牢的瞬間孩革,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工得运, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膝蜈,地道東北人锅移。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像饱搏,于是被迫代替她去往敵國和親非剃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359