本文是經過學習極客時間專欄《Linux性能優化實戰》05 | 基礎篇:某個應用的CPU使用率竟然達到100%,我該怎麼辦?
爲了維護 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
而咱們一般所說的 CPU 使用率,就是除了空閒時間外的其餘時間佔總 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
最後的 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
使用 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。
再往下看是一個表格式樣的數據,每一行包含四列,分別是:工具
仍是以上面的輸出爲例,咱們能夠看到,佔用 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 使用率升高的問題,你能夠藉助 top、pidstat 等工具,確認引起 CPU 性能問題的來源;再使用 perf 等工具,排查出引發性能問題的具體函數。思考