某個應用的CPU使用率竟然達到100%,我該怎麼辦?

本文是經過學習極客時間專欄《Linux性能優化實戰》05 | 基礎篇:某個應用的CPU使用率竟然達到100%,我該怎麼辦?

CPU 使用率


爲了維護 CPU 時間,Linux 經過事先定義的節拍率(內核中表示爲 HZ),觸發時間中斷,並使用全局變量 Jiffies 記錄了開機以來的節拍數。每發生一次時間中斷,Jiffies 的值就加 1。
節拍率 HZ 是內核的可配選項,能夠設置爲 100、250、1000 等。不一樣的系統可能設置不一樣數值,你能夠經過查詢 /boot/config 內核選項來查看它的配置值。好比在個人系統中,節拍率設置成了 250,也就是每秒鐘觸發 250 次時間中斷。php

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

同時,正由於節拍率 HZ 是內核選項,因此用戶空間程序並不能直接訪問。爲了方便用戶空間程序,內核還提供了一個用戶空間節拍率 USER_HZ,它老是固定爲 100,也就是 1/100 秒。這樣,用戶空間程序並不須要關心內核中 HZ 被設置成了多少,由於它看到的老是固定值 USER_HZ。
Linux 經過 /proc 虛擬文件系統,向用戶空間提供了系統內部狀態的信息,而 /proc/stat 提供的就是系統的 CPU 和任務統計信息。比方說,若是你只關注 CPU 的話,能夠執行下面的命令:docker

# 只保留各個CPU的數據
$ 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

這裏的輸出結果是一個表格。其中,第一列表示的是 CPU 編號,如 cpu0、cpu1 ,而第一行沒有編號的 cpu ,表示的是全部 CPU 的累加。其餘列則表示不一樣場景下 CPU 的累加節拍數,它的單位是 USER_HZ,也就是 10 ms(1/100 秒),因此這其實就是不一樣場景下的 CPU 時間。
固然,這裏每一列的順序並不須要你背下來。你只要記住,有須要的時候,查詢 man proc 就能夠。不過,你要清楚 man proc 文檔裏每一列的涵義,它們都是 CPU 使用率相關的重要指標,你還會在不少其餘的性能工具中看到它們。下面,我來依次解讀一下。segmentfault

  • user(一般縮寫爲 us),表明用戶態 CPU 時間。注意,它不包括下面的 nice 時間,但包括了 guest 時間。
  • nice(一般縮寫爲 ni),表明低優先級用戶態 CPU 時間,也就是進程的 nice 值被調整爲 1-19 之間時的 CPU 時間。這裏注意,nice 可取值範圍是 -20 到 19,數值越大,優先級反而越低。
  • system(一般縮寫爲 sys),表明內核態 CPU 時間。
  • idle(一般縮寫爲 id),表明空閒時間。注意,它不包括等待 I/O 的時間(iowait)。
  • iowait(一般縮寫爲 wa),表明等待 I/O 的 CPU 時間。
  • irq(一般縮寫爲 hi),表明處理硬中斷的 CPU 時間。
  • softirq(一般縮寫爲 si),表明處理軟中斷的 CPU 時間。
  • steal(一般縮寫爲 st),表明當系統運行在虛擬機中的時候,被其餘虛擬機佔用的 CPU 時間。
  • guest(一般縮寫爲 guest),表明經過虛擬化運行其餘操做系統的時間,也就是運行虛擬機的 CPU 時間。
  • guest_nice(一般縮寫爲 gnice),表明以低優先級運行虛擬機的時間。

而咱們一般所說的 CPU 使用率,就是除了空閒時間外的其餘時間佔總 CPU 時間的百分比,用公式來表示就是:
file性能優化

怎麼查看 CPU 使用率

top 和 ps 是最經常使用的性能分析工具:top 顯示了系統整體的 CPU 和內存使用狀況,以及各個進程的資源使用狀況。ps 則只顯示了每一個進程的資源使用狀況。併發

# 默認每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
...

這個輸出結果中,top 默認顯示的是全部 CPU 的平均值,這個時候你只須要按下數字 1 ,就能夠切換到每一個 CPU 的使用率了。
繼續往下看,空白行以後是進程的實時信息,每一個進程都有一個 %CPU 列,表示進程的 CPU 使用率。它是用戶態和內核態 CPU 使用率的總和,包括進程用戶空間使用的 CPU、經過系統調用執行的內核空間 CPU 、以及在就緒隊列等待運行的 CPU。在虛擬化環境中,它還包括了運行虛擬機佔用的 CPU。
用 pidstat 吧,它正是一個專門分析每一個進程 CPU 使用狀況的工具。
下面的 pidstat 命令,就間隔 1 秒展現了進程的 5 組 CPU 使用率,包括:app

  • 用戶態 CPU 使用率 (%usr);
  • 內核態 CPU 使用率(%system);
  • 運行虛擬機 CPU 使用率(%guest);
  • 等待 CPU 使用率(%wait);
  • 以及總的 CPU 使用率(%CPU)。

最後的 Average 部分,還計算了 5 組數據的平均值。函數

# 每隔1秒輸出一組數據,共輸出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 使用率太高怎麼辦?

使用 perf 分析 CPU 性能問題,我來講兩種最多見、也是我最喜歡的用法。
第一種常見用法是 perf top,相似於 top,它可以實時顯示佔用 CPU 時鐘最多的函數或者指令,所以能夠用來查找熱點函數,使用界面以下所示:php-fpm

$ 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
...

輸出結果中,第一行包含三個數據,分別是採樣數(Samples)、事件類型(event)和事件總數量(Event count)。好比這個例子中,perf 總共採集了 833 個 CPU 時鐘事件,而總事件數則爲 97742399。
再往下看是一個表格式樣的數據,每一行包含四列,分別是:工具

  • 第一列 Overhead ,是該符號的性能事件在全部採樣中的比例,用百分比來表示。
  • 第二列 Shared ,是該函數或指令所在的動態共享對象(Dynamic Shared Object),如內核、進程名、動態連接庫名、內核模塊名等。
  • 第三列 Object ,是動態共享對象的類型。好比 [.] 表示用戶空間的可執行程序、或者動態連接庫,而 [k] 則表示內核空間。
  • 最後一列 Symbol 是符號名,也就是函數名。當函數名未知時,用十六進制的地址來表示。

仍是以上面的輸出爲例,咱們能夠看到,佔用 CPU 時鐘最多的是 perf 工具自身,不過它的比例也只有 7.28%,說明系統並無 CPU 性能問題。 perf top 的使用你應該很清楚了吧。
接着再來看第二種常見用法,也就是 perf record 和 perf report。 perf top 雖然實時展現了系統的性能信息,但它的缺點是並不保存數據,也就沒法用於離線或者後續的分析。而 perf record 則提供了保存數據的功能,保存後的數據,須要你用 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的報告

測試一下這個 Nginx 服務的性能

# 併發10個請求測試Nginx性能,總共測試100個請求
$ ab -c 10 -n 10000 http://192.168.0.10:10000/
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, 
...
Requests per second: 11.63 [#/sec] (mean)
Time per request: 859.942 [ms] (mean)
...

新開一個終端運行 top 命令,並按下數字 1 ,切換到每一個 CPU 的使用率:

$ top

怎麼知道是 php-fpm 的哪一個函數致使了 CPU 使用率升高呢?咱們來用 perf 分析一下。在第一個終端運行下面的 perf 命令:

# -g開啓調用關係分析,-p指定php-fpm的進程號21515
$ perf top -g -p 21515

小結

CPU 使用率是最直觀和最經常使用的系統性能指標,更是咱們在排查性能問題時,一般會關注的第一個指標。因此咱們更要熟悉它的含義,尤爲要弄清楚用戶(%user)、Nice(%nice)、系統(%system) 、等待 I/O(%iowait) 、中斷(%irq)以及軟中斷(%softirq)這幾種不一樣 CPU 的使用率。好比說:

  • 用戶 CPU 和 Nice CPU 高,說明用戶態進程佔用了較多的 CPU,因此應該着重排查進程的性能問題。
  • 系統 CPU 高,說明內核態佔用了較多的 CPU,因此應該着重排查內核線程或者系統調用的性能問題。
  • I/O 等待 CPU 高,說明等待 I/O 的時間比較長,因此應該着重排查系統存儲是否是出現了 I/O 問題。
  • 軟中斷和硬中斷高,說明軟中斷或硬中斷的處理程序佔用了較多的 CPU,因此應該着重排查內核中的中斷服務程序。

碰到 CPU 使用率升高的問題,你能夠藉助 top、pidstat 等工具,確認引起 CPU 性能問題的來源;再使用 perf 等工具,排查出引發性能問題的具體函數。思考

相關文章
相關標籤/搜索