如何迅速分析出系統CPU的瓶頸在哪裏?

內容出自極客時間專欄《Linux 性能優化實戰》

CPU 的性能指標那麼多,CPU 性能分析工具一抓一大把,換成實際的工作場景,該觀察什麼指標、選擇哪個性能工具呢?

不要擔心,今天我就以多年的性能優化經驗,爲你總結出一個“又快又準”的瓶頸定位套路,告訴你在不同場景下,指標工具怎麼選,性能瓶頸怎麼找。

CPU 性能指標

我們先來回顧下,描述 CPU 的性能指標都有哪些。你可以自己先找張紙,憑着記憶寫一寫;或者打開前面的文章,自己總結一下。

首先,最容易想到的應該是 CPU 使用率,這也是實際環境中最常見的一個性能指標。

CPU 使用率描述了非空閒時間佔總 CPU 時間的百分比,根據 CPU 上運行任務的不同,又被分爲用戶CPU、系統CPU、等待I/O CPU、軟中斷和硬中斷等。

  • 用戶 CPU 使用率,包括用戶態 CPU 使用率(user)和低優先級用戶態 CPU 使用率(nice),表示 CPU 在用戶態運行的時間百分比。用戶 CPU 使用率高,通常說明有應用程序比較繁忙。
  • 系統 CPU 使用率,表示 CPU 在內核態運行的時間百分比(不包括中斷)。系統 CPU 使用率高,說明內核比較繁忙。
  • 等待 I/O 的CPU使用率,通常也稱爲iowait,表示等待 I/O 的時間百分比。iowait 高,通常說明系統與硬件設備的 I/O 交互時間比較長。
  • 軟中斷和硬中斷的 CPU 使用率,分別表示內核調用軟中斷處理程序、硬中斷處理程序的時間百分比。它們的使用率高,通常說明系統發生了大量的中斷。
  • 除了上面這些,還有在虛擬化環境中會用到的竊取 CPU 使用率(steal)和客戶 CPU 使用率(guest),分別表示被其他虛擬機佔用的 CPU 時間百分比,和運行客戶虛擬機的 CPU 時間百分比。

第二個比較容易想到的,應該是平均負載(Load Average),也就是系統的平均活躍進程數。它反應了系統的整體負載情況,主要包括三個數值,分別指過去1分鐘、過去5分鐘和過去15分鐘的平均負載。

理想情況下,平均負載等於邏輯 CPU 個數,這表示每個 CPU 都恰好被充分利用。如果平均負載大於邏輯CPU個數,就表示負載比較重了。

第三個,也是在專欄學習前你估計不太會注意到的,進程上下文切換,包括:

  • 無法獲取資源而導致的自願上下文切換;
  • 被系統強制調度導致的非自願上下文切換。

上下文切換,本身是保證 Linux 正常運行的一項核心功能。但過多的上下文切換,會將原本運行進程的 CPU 時間,消耗在寄存器、內核棧以及虛擬內存等數據的保存和恢復上,縮短進程真正運行的時間,成爲性能瓶頸。

除了上面幾種,還有一個指標,CPU緩存的命中率。由於CPU發展的速度遠快於內存的發展,CPU的處理速度就比內存的訪問速度快得多。這樣,CPU在訪問內存的時候,免不了要等待內存的響應。爲了協調這兩者巨大的性能差距,CPU緩存(通常是多級緩存)就出現了。

就像上面這張圖顯示的,CPU緩存的速度介於CPU和內存之間,緩存的是熱點的內存數據。根據不斷增長的熱點數據,這些緩存按照大小不同分爲 L1、L2、L3 等三級緩存,其中 L1 和 L2 常用在單核中, L3 則用在多核中。

從 L1 到 L3,三級緩存的大小依次增大,相應的,性能依次降低(當然比內存還是好得多)。而它們的命中率,衡量的是CPU緩存的複用情況,命中率越高,則表示性能越好。

這些指標都很有用,需要我們熟練掌握,所以我總結成了一張圖,幫你分類和記憶。

性能工具

掌握了 CPU 的性能指標,我們還需要知道,怎樣去獲取這些指標,也就是工具的使用。

你還記得前面案例都用了哪些工具嗎?這裏我們也一起回顧一下CPU性能工具。

首先,平均負載的案例。我們先用 uptime, 查看了系統的平均負載;而在平均負載升高後,又用 mpstat 和 pidstat ,分別觀察了每個 CPU 和每個進程 CPU 的使用情況,進而找出了導致平均負載升高的進程,也就是我們的壓測工具 stress。

第二個,上下文切換的案例。我們先用 vmstat ,查看了系統的上下文切換次數和中斷次數;然後通過 pidstat ,觀察了進程的自願上下文切換和非自願上下文切換情況;最後通過 pidstat ,觀察了線程的上下文切換情況,找出了上下文切換次數增多的根源,也就是我們的基準測試工具 sysbench。

第三個,進程 CPU 使用率升高的案例。我們先用 top ,查看了系統和進程的CPU使用情況,發現 CPU 使用率升高的進程是 php-fpm;再用 perf top ,觀察 php-fpm 的調用鏈,最終找出 CPU 升高的根源,也就是庫函數 sqrt() 。

第四個,系統的 CPU 使用率升高的案例。我們先用 top 觀察到了系統CPU升高,但通過 top 和 pidstat ,卻找不出高 CPU 使用率的進程。於是,我們重新審視 top 的輸出,又從 CPU 使用率不高但處於 Running 狀態的進程入手,找出了可疑之處,最終通過 perf record 和 perf report ,發現原來是短時進程在搗鬼。

另外,對於短時進程,我還介紹了一個專門的工具 execsnoop,它可以實時監控進程調用的外部命令。

第五個,不可中斷進程和殭屍進程的案例。我們先用 top 觀察到了 iowait 升高的問題,並發現了大量的不可中斷進程和殭屍進程;接着我們用 dstat 發現是這是由磁盤讀導致的,於是又通過 pidstat 找出了相關的進程。但我們用 strace 查看進程系統調用卻失敗了,最終還是用 perf 分析進程調用鏈,才發現根源在於磁盤直接 I/O 。

最後一個,軟中斷的案例。我們通過 top 觀察到,系統的軟中斷 CPU 使用率升高;接着查看 /proc/softirqs, 找到了幾種變化速率較快的軟中斷;然後通過 sar 命令,發現是網絡小包的問題,最後再用 tcpdump ,找出網絡幀的類型和來源,確定是一個 SYN FLOOD 攻擊導致的。

到這裏,估計你已經暈了吧,原來短短几個案例,我們已經用過十幾種 CPU 性能工具了,而且每種工具的適用場景還不同呢!這麼多的工具要怎麼區分呢?在實際的性能分析中,又該怎麼選擇呢?

我的經驗是,從兩個不同的維度來理解它們,做到活學活用。

活學活用,把性能指標和性能工具聯繫起來

第一個維度,從 CPU 的性能指標出發。也就是說,當你要查看某個性能指標時,要清楚知道哪些工具可以做到。

根據不同的性能指標,對提供指標的性能工具進行分類和理解。這樣,在實際排查性能問題時,你就可以清楚知道,什麼工具可以提供你想要的指標,而不是毫無根據地挨個嘗試,撞運氣。

其實,我在前面的案例中已經多次用到了這個思路。比如用 top 發現了軟中斷 CPU 使用率高後,下一步自然就想知道具體的軟中斷類型。那在哪裏可以觀察各類軟中斷的運行情況呢?當然是 proc 文件系統中的 /proc/softirqs 這個文件。

緊接着,比如說,我們找到的軟中斷類型是網絡接收,那就要繼續往網絡接收方向思考。系統的網絡接收情況是什麼樣的?什麼工具可以查到網絡接收情況呢?在我們案例中,用的正是 dstat。

雖然你不需要把所有工具背下來,但如果能理解每個指標對應的工具的特性,一定更高效、更靈活地使用。這裏,我把提供 CPU 性能指標的工具做成了一個表格,方便你梳理關係和理解記憶,當然,你也可以當成一個“指標工具”指南來使用。

下面,我們再來看第二個維度。

第二個維度,從工具出發。也就是當你已經安裝了某個工具後,要知道這個工具能提供哪些指標。這在實際環境特別是生產環境中也是非常重要的,因爲很多情況下,你並沒有權限安裝新的工具包,只能最大化地利用好系統中已經安裝好的工具,這就需要你對它們有足夠的瞭解。

具體到每個工具的使用方法,一般都支持豐富的配置選項。不過不用擔心,這些配置選項並不用背下來。你只要知道有哪些工具、以及這些工具的基本功能是什麼就夠了。真正要用到的時候, 通過man 命令,查它們的使用手冊就可以了。

同樣的,我也將這些常用工具彙總成了一個表格,方便你區分和理解,自然,你也可以當成一個“工具指標”指南使用,需要時查表即可。

如何迅速分析CPU的性能瓶頸

我相信到這一步,你對 CPU 的性能指標已經非常熟悉,也清楚每種性能指標分別能用什麼工具來獲取。

那是不是說,每次碰到 CPU 的性能問題,你都要把上面這些工具全跑一遍,然後再把所有的 CPU 性能指標全分析一遍呢?

你估計覺得這種簡單查找的方式,就像是在傻找。不過,別笑話,因爲最早的時候我就是這麼做的。把所有的指標都查出來再統一分析,當然是可以的,也很可能找到系統的潛在瓶頸。

但是這種方法的效率真的太低了!耗時耗力不說,在龐大的指標體系面前,你一不小心可能就忽略了某個細節,導致白乾一場。我就吃過好多次這樣的苦。

所以,在實際生產環境中,我們通常都希望儘可能快地定位系統的瓶頸,然後儘可能快地優化性能,也就是要又快又準地解決性能問題。

那有沒有什麼方法,可以又快又準找出系統瓶頸呢?答案是肯定的。

雖然 CPU 的性能指標比較多,但要知道,既然都是描述系統的CPU性能,它們就不會是完全孤立的,很多指標間都有一定的關聯。想弄清楚性能指標的關聯性,就要通曉每種性能指標的工作原理。這也是爲什麼我在介紹每個性能指標時,都要穿插講解相關的系統原理,希望你能記住這一點。

舉個例子,用戶 CPU 使用率高,我們應該去排查進程的用戶態而不是內核態。因爲用戶 CPU 使用率反映的就是用戶態的 CPU 使用情況,而內核態的 CPU 使用情況只會反映到系統 CPU 使用率上。

你看,有這樣的基本認識,我們就可以縮小排查的範圍,省時省力。

所以,爲了縮小排查範圍,我通常會先運行幾個支持指標較多的工具,如 top、vmstat 和 pidstat 。爲什麼是這三個工具呢?仔細看看下面這張圖,你就清楚了。

這張圖裏,我列出了 top、vmstat 和 pidstat 分別提供的重要的 CPU 指標,並用虛線表示關聯關係,對應出了性能分析下一步的方向。

通過這張圖你可以發現,這三個命令,幾乎包含了所有重要的 CPU 性能指標,比如:

  • 從 top 的輸出可以得到各種 CPU 使用率以及殭屍進程和平均負載等信息。
  • 從 vmstat 的輸出可以得到上下文切換次數、中斷次數、運行狀態和不可中斷狀態的進程數。
  • 從 pidstat 的輸出可以得到進程的用戶 CPU 使用率、系統 CPU 使用率、以及自願上下文切換和非自願上下文切換情況。

另外,這三個工具輸出的很多指標是相互關聯的,所以,我也用虛線表示了它們的關聯關係,舉幾個例子你可能會更容易理解。

第一個例子,pidstat 輸出的進程用戶 CPU 使用率升高,會導致 top 輸出的用戶 CPU 使用率升高。所以,當發現 top 輸出的用戶 CPU 使用率有問題時,可以跟 pidstat 的輸出做對比,觀察是否是某個進程導致的問題。

而找出導致性能問題的進程後,就要用進程分析工具來分析進程的行爲,比如使用 strace 分析系統調用情況,以及使用 perf 分析調用鏈中各級函數的執行情況。

第二個例子,top 輸出的平均負載升高,可以跟 vmstat 輸出的運行狀態和不可中斷狀態的進程數做對比,觀察是哪種進程導致的負載升高。

  • 如果是不可中斷進程數增多了,那麼就需要作 I/O 的分析,也就是用 dstat 或 sar 等工具,進一步分析 I/O 的情況。
  • 如果是運行狀態進程數增多了,那就需要回到 top 和 pidstat,找出這些處於運行狀態的到底是什麼進程,然後再用進程分析工具,做進一步分析。

最後一個例子,當發現 top 輸出的軟中斷 CPU 使用率升高時,可以查看 /proc/softirqs 文件中各種類型軟中斷的變化情況,確定到底是哪種軟中斷出的問題。比如,發現是網絡接收中斷導致的問題,那就可以繼續用網絡分析工具 sar 和 tcpdump 來分析。

注意,我在這個圖中只列出了最核心的幾個性能工具,並沒有列出所有。這麼做,一方面是不想用大量的工具列表嚇到你。在學習之初就接觸所有核心或小衆的工具,不見得是好事。另一方面,是希望你能先把重心放在覈心工具上,畢竟熟練掌握它們,就可以解決大多數問題。

所以,你可以保存下這張圖,作爲CPU性能分析的思路圖譜。從最核心的這幾個工具開始,通過我提供的那些案例,自己在真實環境裏實踐,拿下它們。

推薦專欄《Linux 性能優化實戰》

作爲一個程序員,性能優化是無法避開的事情,也是軟件系統中最有挑戰的工作之一,更是每個工程師都需要掌握的核心技能。專欄最大的特色:作者結合多年的實戰經驗,以案例驅動的思路,爲你講解 Linux 性能的基本指標、工具,以及相應的觀測、分析和調優方法,學後可以立即應用在自己的優化工作中。

上線 3 個月,已有近 1.7W 人加入學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章