Linux性能優化(一)

性能指標

性能優化的兩個核心指標——"吞吐"和"延遲",這是從應用負載的視角來進行考察系統性能,直接影響了產品終端的用戶體驗。與之對應的是從系統資源的視角出發的指標,好比資源使用率、飽和度等。python

 

咱們知道,隨着應用負載的增長,系統資源的使用也會升高,甚至達到極限。而性能問題的本質,就是系統資源已經達到瓶頸,但請求的處理卻還不夠快,沒法支撐更多的請求。ios

性能分析,其實就是找出應用或系統的瓶頸,並設法去避免或者緩解他們,從而更高效地利用系統資源處理更多的請求。這包含了一系列的步驟,好比下面這六個步驟。redis

  • 選擇指標評估應用程序和系統的性能數據庫

  • 爲應用程序和系統設置性能目標緩存

  • 進行性能基準測試性能優化

  • 性能分析定位瓶頸bash

  • 優化系統和應用程序服務器

  • 性能監控和告警多線程

這個圖是Linux性能分析最重要的參考資料之一,它告訴你,在Linux不一樣子系統出現性能問題後,應該用什麼樣的工具來觀測和分析。app

好比,當遇到IO性能問題時,能夠參考圖片下方的IO子系統,使用iostat、iotop、blktrace等工具分析磁盤IO的瓶頸。

理解平均負載

平均負載

平均負載是指單位時間內,系統處於可運行狀態和不可中斷狀態的平均進程數,也就是平均活躍進程數,它和CPU使用率並無直接關係。

可運行狀態的進程,是指正在使用CPU或者正在等待CPU的進程,也就是ps命令查看進程狀態中的R狀態(Running或Runnable)。

不可中斷狀態的進程,是指正處於內核態關鍵流程中的進程,而且這些流程是不可打斷的,好比最長間的是等待硬件設備的IO響應,也就是ps命令查看進程狀態中的D狀態。例如,當一個進程向磁盤讀取數據時,爲了保證數據的一致性,在獲得磁盤迴復前,它是不能被其餘進程或者中斷打斷,這個時候的進程處於不可中斷狀態。若是此時的進程被打斷,就容易出現磁盤數據與進程數據不一致的問題。因此,不可中斷狀態其實是系統對進程和硬件設備的一種保護機制。所以平均負載能夠理解爲平均活躍進程數。平均進程活躍數,直觀上的理解就是單位時間內的活躍進程數,但其實是活躍進程數的指數衰減平均值,能夠直接理解爲活躍進程數的平均值。

若是當平均負載爲2時,就意味着

  • 在只有2個CPU的系統上,意味着全部的CPU都恰好被徹底佔用。

  • 在4個CPU的系統上,意味着CPU有50%的空閒。

  • 在1個CPU的系統中,意味着有一半的進程競爭不到CPU

平均負載爲多少時合理

平均負載最理想的狀況是等於CPU個數,因此在評判平均負載時,首先要知道系統有幾個CPU,有了CPU個數,咱們能夠判斷出,當平均負載比CPU個數還大的時候,系統已經出現了過載。

三個不一樣時間間隔的平均負載,其實給咱們提供了,分析系統負載趨勢的數據來源,讓咱們更能全面、更立體地理解目前的負載狀況。

  • 若是1分鐘、5分鐘、15分鐘的三個值基本相同,或者相差不大,那就說明系統負載很平穩。

  • 但若是1分鐘的值遠小於15分鐘的值,就說明系統最近1分鐘的負載在減小,而過去15分鐘內卻有很大的負載

  • 若是1分鐘的值遠大於15分鐘的值,就說明最近1分鐘的負載在增長,這種增長有可能只是臨時性的,也有可能還會持續增長下去,因此就須要持續觀察。一旦1分鐘的平均負載接近或者超過CPU的個數,就意味着系統正在發生過載的問題,這時就得分析調查是哪裏致使的問題,並要想辦法優化。

分析排查負載太高的問題須要把系統的平均負載監控起來,而後根據更多的歷史數據,判斷負載的變化趨勢,當發生負載有明顯升高趨勢時,好比說負載翻倍了,再去作分析和調查

平均負載與CPU使用率

  • CPU密集型進程,使用大量CPU會致使平均負載升高

  • IO密集型進程,等待IO也會致使平均負載升高,單CPU使用率不必定很高。

  • 大量等待CPU的進程調度也會致使平均負載升高,此時的CPU使用率也會比較高。

分析負載工具

CPU場景監控

mpstat是一個經常使用的多核CPU性能分析工具,用來實時查看每一個CPU的性能指標,以及全部CPU的平均指標

[root@localhost ~]# mpstat 2
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain) 	04/27/2020 	_x86_64_	(4 CPU)

05:49:27 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:49:29 PM  all    0.50    0.00    0.50    0.00    0.00    0.00    0.00    0.00   99.00
05:49:31 PM  all    0.38    0.00    0.38    0.00    0.00    0.00    0.00    0.00   99.25
05:49:33 PM  all    0.25    0.00    0.50    0.00    0.00    0.00    0.00    0.00   99.25
05:49:35 PM  all    0.25    0.00    0.50    0.00    0.00    0.00    0.00    0.00   99.25

pidstat是一個經常使用的進程性能分析工具,用來實時查看進程的CPU、內存、IO以及山下文切換等性能指標。  

[root@localhost ~]# stress --cpu 1 --timeout 600
stress: info: [6168] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd

[root@localhost ~]# uptime
17:59:36 up 405 days,  8:51,  2 users,  load average: 0.99, 0.75, 0.35

[root@localhost ~]# mpstat -P ALL 2 3
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain) 	04/27/2020 	_x86_64_	(4 CPU)

05:57:44 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:57:46 PM  all   25.41    0.00    0.50    0.00    0.00    0.00    0.00    0.00   74.09
05:57:46 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
05:57:46 PM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
05:57:46 PM    2    1.01    0.00    0.00    0.00    0.00    0.00    0.00    0.00   98.99
05:57:46 PM    3    0.00    0.00    2.01    0.00    0.00    0.00    0.00    0.00   97.99

05:57:46 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
05:57:48 PM  all   25.37    0.00    0.50    0.00    0.00    0.00    0.00    0.00   74.12
05:57:48 PM    0    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00  100.00
05:57:48 PM    1  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
05:57:48 PM    2    1.00    0.00    0.50    0.00    0.00    0.00    0.00    0.00   98.50
05:57:48 PM    3    1.00    0.00    1.49    0.00    0.00    0.00    0.00    0.00   97.51

[root@localhost ~]# pidstat -u 5 1
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain) 	04/27/2020 	_x86_64_	(4 CPU)

06:08:20 PM       PID    %usr %system  %guest    %CPU   CPU  Command
06:08:25 PM      3360    0.00    0.20    0.00    0.20     0  redis-server
06:08:25 PM      3593    0.20    0.20    0.00    0.40     3  bash
06:08:25 PM      3723    0.60    0.20    0.00    0.80     0  netdata
06:08:25 PM      3748    0.20    0.00    0.00    0.20     0  python
06:08:25 PM      7276  100.00    0.00    0.00  100.00     1  stress
06:08:25 PM      7289    0.00    0.20    0.00    0.20     3  pidstat
06:08:25 PM     25850    0.40    1.00    0.00    1.40     2  apps.plugin

Average:          PID    %usr %system  %guest    %CPU   CPU  Command
Average:         3360    0.00    0.20    0.00    0.20     -  redis-server
Average:         3593    0.20    0.20    0.00    0.40     -  bash
Average:         3723    0.60    0.20    0.00    0.80     -  netdata
Average:         3748    0.20    0.00    0.00    0.20     -  python
Average:         7276  100.00    0.00    0.00  100.00     -  stress
Average:         7289    0.00    0.20    0.00    0.20     -  pidstat
Average:        25850    0.40    1.00    0.00    1.40     -  apps.plugin

首先利用stress模擬一個CPU使用率100%的狀況,而後利用uptime觀察平均負載的變化狀況,最後使用mpstat查看每一個CPU使用率的狀況;從uptime命令能夠看到1分鐘內的平均負載==1,而mpstat命令看到CPU1的使用率爲100%,且都是在用戶態空間使用的CPU,說明致使負載升高是因爲CPU使用率比較高引發的負載升高;最後使用pidstat監測,發現是stress進程CPU使用爲100%

IO密集型應用

[root@localhost ~]# stress -i 1 --timeout 600
stress: info: [7582] dispatching hogs: 0 cpu, 1 io, 0 vm, 0 hdd


[root@localhost ~]# uptime
 18:13:11 up 405 days,  9:05,  2 users,  load average: 0.80, 0.66, 0.46
[root@localhost ~]# uptime
 18:13:16 up 405 days,  9:05,  2 users,  load average: 0.82, 0.66, 0.47
[root@localhost ~]# uptime
 18:13:24 up 405 days,  9:05,  2 users,  load average: 0.84, 0.67, 0.47
[root@localhost ~]# uptime
 18:13:30 up 405 days,  9:05,  2 users,  load average: 0.86, 0.68, 0.47
[root@localhost ~]# uptime
 18:13:39 up 405 days,  9:05,  2 users,  load average: 0.88, 0.69, 0.48
[root@localhost ~]# uptime
 18:13:47 up 405 days,  9:05,  2 users,  load average: 0.90, 0.70, 0.48
[root@localhost ~]# uptime
 18:14:05 up 405 days,  9:06,  2 users,  load average: 0.92, 0.71, 0.49
[root@localhost ~]# uptime
 18:14:22 up 405 days,  9:06,  2 users,  load average: 0.94, 0.73, 0.50
[root@localhost ~]# uptime
 18:14:47 up 405 days,  9:06,  2 users,  load average: 0.96, 0.74, 0.51
[root@localhost ~]# uptime
 18:15:28 up 405 days,  9:07,  2 users,  load average: 0.98, 0.78, 0.53
 
[root@localhost ~]# mpstat -P ALL 5 1
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/27/2020     _x86_64_    (4 CPU)

06:17:07 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
06:17:12 PM  all    0.35    0.00   24.90    0.05    0.00    0.00    0.00    0.00   74.70
06:17:12 PM    0    0.00    0.00    0.40    0.00    0.00    0.00    0.00    0.00   99.60
06:17:12 PM    1    0.00    0.00   97.79    0.00    0.00    0.00    0.00    0.00    2.21
06:17:12 PM    2    0.40    0.00    1.20    0.00    0.00    0.00    0.00    0.00   98.40
06:17:12 PM    3    0.81    0.00    0.60    0.00    0.00    0.00    0.00    0.00   98.59

Average:     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
Average:     all    0.35    0.00   24.90    0.05    0.00    0.00    0.00    0.00   74.70
Average:       0    0.00    0.00    0.40    0.00    0.00    0.00    0.00    0.00   99.60
Average:       1    0.00    0.00   97.79    0.00    0.00    0.00    0.00    0.00    2.21
Average:       2    0.40    0.00    1.20    0.00    0.00    0.00    0.00    0.00   98.40
Average:       3    0.81    0.00    0.60    0.00    0.00    0.00    0.00    0.00   98.59

Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/27/2020     _x86_64_    (4 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00     6.62    0.00    0.28     0.10    55.18   197.39     0.00   16.34   17.61   16.33   2.20   0.06
sdb               0.00     8.30    0.00    0.14     0.09    67.52   466.32     0.00   19.77   11.13   19.87   1.55   0.02
dm-0              0.00     0.00    0.01   15.34     0.19   122.70     8.01     0.03    2.04   22.82    2.03   0.05   0.08
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     8.00     0.00    9.10    9.16    8.86   6.09   0.00

能夠看到結合iostat分析發現致使負載升高的是IO致使系統負載升高

[root@localhost ~]# stress -c 8 --timeout 600
stress: info: [8429] dispatching hogs: 8 cpu, 0 io, 0 vm, 0 hdd

利用stress -c 8 --timeout 600能夠模擬更加複雜的場景

CPU上下文切換

Linux是一個多任務操做系統,它支持遠大於CPU數量的任務同時運行。固然,這些任務實際上並非真的在同時運行,而是由於系統在很短的時間內,將CPU輪流分配給它們,形成多任務同時運行的錯覺。每一個任務運行前,CPU都須要知道任務從哪裏加載,又從哪裏開始運行,也就是說,須要系統事先幫它設置好CPU寄存器和程序計數器。CPU寄存器,是CPU內置的容量小,但速度極快的內存。程序計數器,則是用來存儲CPU正在執行的指令位置,或者即將執行的下一條指令位置。它們都是CPU在運行任務前,必須的依賴環境,所以也被叫作CPU上下文。

CPU上下文切換,就是先把前一個任務的CPU上下文保存起來,而後加載新任務的上下文到這些寄存器和程序計數器,最後再跳轉到程序計數器所指的新位置,運行新任務。而這些保存下來的上下文,會存儲在系統內核中,並在任務從新調度執行時再次加載進來。這樣就能保證任務原來的狀態不受影響,讓任務看起來仍是連續執行。

根據任務的不一樣,CPU的上下文切換就能夠分爲進程上下文切換、線程上下文切換以及中斷上下文切換。

進程上下文切換

Linux按照特權等級,把進程的運行空間分爲內核空間和用戶空間,分別對應着下圖中,CPU特權等級的Ring0和Ring3。

  • 內核空間(Ring0)具備最高權限,能夠直接訪問全部資源;

  • 用戶空間(Ring3)只能訪問受限資源,不能直接訪問內存等硬件設備,必須經過系統調用陷入到內核中,才能訪問這些特權資源。

也就是說,進程既能夠在用戶空間運行,又能夠在內核空間中運行。進程在用戶空間運行時,被稱爲進程的用戶態,而陷入內核空間的時候,被稱爲進程的內核態。

從用戶態到內核態的轉變,須要經過系統調用來完成。好比,當咱們查看文件內容時,就須要屢次系統調用來完成:首先調用open()打開文件,而後調用read()讀取文件內容,並調用write()將內容寫到標準輸出,最後再調用close()關閉文件。

CPU寄存器裏原來用戶態的指令位置,須要先保存起來。接着,爲了執行內核態代碼,CPU寄存器須要更新爲內核態指令的新位置,最後纔是跳轉到內核態運行內核任務。

而系統調用結束後,CPU寄存器須要恢復原來保存的用戶態,而後在切換到用戶空間,繼續運行進程。因此,一次系統調用的過程,實際上是發生了兩次CPU上下文切換。

不過,須要注意的是,系統調用過程當中,並不會涉及到虛擬內存等進程用戶的資源,也不會切換進程。這與咱們一般所說的進程上下文切換是不同的:

  • 進程上下文切換,是指從一個進程切換到另外一個進程運行。

  • 而系統調用過程當中一直是同一個進程在運行。

因此,系統調用過程一般稱爲特權模式切換,而不是上下文切換。但實際上,系統調用過程當中,CPU的上下文切換仍是沒法避免的。

進程上下文切換跟系統調用的區別:

首先,須要知道,進程是由內核來管理和調度的,進程的切換隻能發生在內核態。因此,進程的上下文不只包括了虛擬內存、棧、全局變量等用戶空間的資源,還包括了內核堆棧、寄存器等內核空間的狀態。

所以,進程上下文切換就比系統調用多了一步:在保存當前進程的內核狀態和CPU寄存器以前,須要先把該進程的虛擬內存、棧等保存下來;而加載了下一進程的內核態後,還須要刷新進程的虛擬內存和用戶棧。

以下圖所示,保存上下文和恢復上下文的過程並非免費的,須要內核在CPU上運行才能完成。

 

根據研究代表,每次上下文切換都須要幾十納秒到數微秒的CPU時間,這個時間仍是至關可觀的,特別是在進程上下文切換次數較多的狀況下,很容易致使CPU將大量時間耗費在寄存器、內核棧以及虛擬內存等資源的保存和恢復上,進而大大縮短了真正運行進程的時間。這也是致使平均負載上升的一個重要因素。

Linux經過TLB來管理虛擬內存到物理內存的映射關係。當虛擬內存更新後,TLB也須要刷新,內存的訪問也會隨之變慢。特別是在多處理系統上,緩存是被多個處理器共享的,刷新緩存不只會影響當前處理器的進程,還會影響共享緩存的其餘處理器的進程。

顯然,進程切換時才須要切換上下文,換句話說,只有在進程調度的時候,才須要切換上下文。Linux爲每一個CPU都維護了一個就緒隊列,將活躍進程(即正在運行和正在等待CPU的進程)按照優先級和等待CPU的時間排序,而後選擇最須要CPU的進程,這也就是優先級最高和等待CPU時間最長的進程來運行。

觸發進程調度的場景:

  • 爲了保證全部進程能夠獲得公平調度,CPU時間被劃分爲一段段的時間片,這些時間片再被輪流分配給各個進程。這樣,當某個進程的時間片耗盡了,就會被系統掛起,切換到其它正在等待CPU的進程執行。

  • 進程在系統資源不足時,要等到資源知足後才能夠運行,這個時候進程也會被掛起,並由系統調度其它進程運行。

  • 當進程經過睡眠函數sleep這樣的方法將本身主動掛起時,天然也會從新調度。

  • 當有優先級更高的進程運行時,爲了保證高優先級進程的運行,當前進程會被掛起,由高優先級進程來運行。

  • 當發生硬中斷時,CPU上的進程會被掛起,轉而執行內核中的中斷服務程序。

線程上下文切換

線程與進程最大的區別在於,線程是調度的基本單位,而進程則是資源擁有的基本單位。所謂內核中的任務調度,實際上的調度對象是線程;而進程只是給線程提供了虛擬內存、全局變量等資源。因此,對於線程和進程能夠這麼理解:

  • 當進程只有一個線程時,能夠認爲進程就等於線程。

  • 當進程擁有多個線程時,這些線程會共享相同的虛擬內存和全局變量等資源。這些資源在上下文切換時是不須要修改的。

  • 線程也有本身的私有數據,好比棧和寄存器等,這些在上下文切換時也是須要保存的。

所以,線程的上下文切換其實就能夠分爲兩種狀況:

第一種,先後兩個線程屬於不一樣進程。此時,資源不一樣享,因此切換過程就跟進程上下文切換是同樣的。

第二種,先後兩個線程屬於同一個進程。此時,虛擬內存是共享的,因此在切換時,虛擬內存這些資源就保持不動,只須要切換線程的私有數據、寄存器等不一樣享數據。

經過以上狀況能夠發現,雖然同爲上下文切換,但同進程內的線程切換,要比多進程間切換消耗更少的資源,而這,也正是多線程代替多進程的一個優點。

中斷上下文切換

切換進程CPU上下文,其實就是中斷上下文切換。爲了快速響應硬件的事件,中斷處理會打斷進程的正常調度和執行,轉而調用中斷處理程序,響應設備事件。而在打斷其餘進程時,就須要將進程當前狀態保存下來,這樣在中斷結束後,進程仍然能夠從原來的狀態恢復運行。

跟進程上下文不一樣,中斷上下文切換並不涉及到進程的用戶態。因此,即使中斷過程打斷了一個正處在用戶態的進程,也不須要保存和恢復這個進程的虛擬內存、全局變量等用戶態資源。中斷上下文,其實只包括內核態中斷服務程序執行所必須的狀態,包括CPU寄存器、內核堆棧、硬件中斷參數等。

對同一個CPU來講,中斷處理比進程擁有更高的優先級,因此中斷上下文切換並不會與進程上下文切換同時發生。一樣道理,因爲中斷會打斷正常進程的調度和執行,因此大部分中斷處理程序都短小精悍,以便儘量快的執行結束。

另外,跟進程上下文切換同樣,中斷上下文切換也須要消耗CPU,切換次數過多也會消耗大量的CPU,甚至嚴重下降系統的總體性能。因此,當發現中斷次數過多時,就須要注意去排查它是否會給系統帶來嚴重的性能問題。

CPU上下文切換分析

查看系統上下文

利用vmstat工具來進行查看上下文切換,例如:

[root@localhost ~]# vmstat 2
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0    384 1303264 215296 12506412    0    0     0    15    0    0  1  1 98  0  0    
 0  0    384 1303256 215296 12506412    0    0     0     0  237  201  0  0 99  0  0    
 0  0    384 1303000 215296 12506412    0    0     0     8  290  227  1  1 99  0  0    
 0  0    384 1302884 215296 12506412    0    0     0     0  227  206  0  1 99  0  0    
 0  0    384 1302628 215296 12506412    0    0     0     0  250  231  0  1 99  0  0
  • cs是每秒上下文切換的次數

  • in則是每秒鐘中斷的次數

  • r是就緒隊列的長度,也就是正在運行和等待CPU的進程數

  • b則是出於不可中斷睡眠狀態的進程數

能夠看到,這個例子中的上線文切換次數cs是201次,而系統中斷in則是237次,而就緒隊列長度r和不可中斷狀態進程數b都是0。

vmstat只給出了系統整體的上下文切換狀況,要向查看每一個進程的詳細狀況,就須要使用到pidstat了,以下:

[root@localhost ~]# pidstat -w 5
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/29/2020     _x86_64_    (4 CPU)

05:00:25 PM       PID   cswch/s nvcswch/s  Command
05:00:30 PM         3      0.20      0.00  migration/0
05:00:30 PM         4      0.20      0.00  ksoftirqd/0
05:00:30 PM         7      0.40      0.00  migration/1
05:00:30 PM         9      0.20      0.00  ksoftirqd/1
05:00:30 PM        13      0.20      0.00  ksoftirqd/2
05:00:30 PM        15      0.60      0.00  migration/3
05:00:30 PM        17      2.40      0.00  ksoftirqd/3
05:00:30 PM        19      1.20      0.00  events/0
05:00:30 PM        20      1.00      0.00  events/1
05:00:30 PM        21      1.00      0.00  events/2
05:00:30 PM        22      1.00      0.00  events/3
05:00:30 PM        28      0.20      0.00  sync_supers
05:00:30 PM        29      0.20      0.00  bdi-default
05:00:30 PM       197      1.00      0.00  mpt_poll_0
05:00:30 PM       353      0.20      0.00  flush-253:0
05:00:30 PM       598      1.00      0.00  vmmemctl
05:00:30 PM      1202      0.40      0.00  master
05:00:30 PM      1231      1.00      0.00  zabbix_agentd
05:00:30 PM      1235      1.00      0.00  zabbix_agentd
05:00:30 PM      2912      2.00      0.00  bash
05:00:30 PM      3360     10.98      0.00  redis-server
05:00:30 PM      3748      1.00      0.20  python
05:00:30 PM      5830      0.40      0.00  showq
05:00:30 PM      5883      0.20      0.00  pidstat
05:00:30 PM     29194      1.00      1.60  apps.plugin

這個結果中有兩列內容是咱們重點關注的對象。一個是cswch,表示每秒自願上下文切換的次數,另外一個則是mbcswch,表示每秒非自願上下文切換的次數。

這兩個概念意味着不一樣的性能問題:

  • 自願上下文切換,是指進程沒法獲取所需自願,致使上下文切換。好比,IO、內存等系統資源不足時,就會發生自願上下文切換。

  • 非自願上下文切換,則是指進程因爲時間片已到等緣由,被系統強制調度,進而發生的上下文切換。好比說,大量進程都在爭搶CPU時,就容易發生非自願上下文切換。

模擬場景

使用sysbench來模擬系統多線程調度切換的狀況。

sysbench是一個多線程的基準測試工具,通常用來評估不一樣系統參數下的數據庫負載狀況,能夠用來模擬上下文切換過多的問題。

測試前的數據查看狀況

[root@localhost ~]# vmstat 1 
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0    384 1302564 215296 12506416    0    0     0    15    0    0  1  1 98  0  0    
 0  0    384 1302556 215296 12506416    0    0     0     0  257  207  1  1 99  0  0    
 0  0    384 1302556 215296 12506416    0    0     0     0  223  192  1  1 99  0  0    
 0  0    384 1302440 215296 12506416    0    0     0     0  257  219  1  1 99  0  0    
 0  0    384 1302176 215296 12506416    0    0     0     4  248  225  0  0 99  0  0    
 0  0    384 1302176 215296 12506416    0    0     0     0  218  203  1  1 99  0  0    
 0  0    384 1303044 215296 12506416    0    0     0     0  371  239  1  1 98  0  0    
 0  0    384 1302804 215296 12506416    0    0     0     0  232  213  0  1 99  0  0

在終端離運行sysbench,模擬系統多線程調度的瓶頸:

[root@localhost ~]# sysbench --threads=10 --max-time=300 threads run
WARNING: --max-time is deprecated, use --time instead
sysbench 1.0.17 (using system LuaJIT 2.0.4)

Running the test with following options:
Number of threads: 10
Initializing random number generator from current time


Initializing worker threads...

Threads started!

執行sysbench後,使用vmstat來進行監控:

[root@localhost ~]# vmstat 2
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0    384 1297912 215400 12509840    0    0     0    15    0    0  1  1 98  0  0    
 2  0    384 1298036 215400 12509840    0    0     0    10  279  214  1  1 99  0  0    
 1  0    384 1298052 215400 12509840    0    0     0     0  241  202  1  1 99  0  0    
 8  0    384 1296716 215400 12509840    0    0     0     0 7069 257920  3 39 57  0  0    
 8  0    384 1296468 215400 12509840    0    0     0     0 17640 477390  7 80 13  0  0    
10  0    384 1295592 215400 12509840    0    0     0     0 18891 657740  6 85  9  0  0    
 8  0    384 1295724 215400 12509840    0    0     0     0 19504 597917  7 82 11  0  0    

觀測數據能夠發現:

  • r列:就緒隊列的長度已經到8,遠遠超過了系統CPU的個數2,因此確定會有大量的CPU競爭。

  • us和sy列:這兩列的CPU使用率加起來上升到了100%,其中系統CPU使用率,也就是sy列高達80%左右,說明CPU主要是被內核佔用了。

  • in列:中斷次數也上升到了將近2萬左右,說明中斷處理也是個潛在的問題。

vmstat詳解以下:

綜合這幾個指標,能夠知道,系統的就緒隊列過長,也就是正在運行和等待CPU的進程數過多,致使了大量的上下文切換,而上下文切換又致使了系統CPU的佔用率升高。

使用pidstat來進行觀察,CPU和進程上下文的狀況:

[root@localhost ~]# pidstat -w -u 1
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/29/2020     _x86_64_    (4 CPU)

05:25:40 PM       PID    %usr %system  %guest    %CPU   CPU  Command
05:25:41 PM        17    0.00    0.98    0.00    0.98     3  ksoftirqd/3
05:25:41 PM      3360    0.98    0.98    0.00    1.96     1  redis-server
05:25:41 PM      3723    1.96    0.98    0.00    2.94     1  netdata
05:25:41 PM      7661   28.43  100.00    0.00  100.00     1  sysbench
05:25:41 PM      7698    0.00    0.98    0.00    0.98     3  pidstat
05:25:41 PM     29194    0.98    0.98    0.00    1.96     1  apps.plugin

05:25:40 PM       PID   cswch/s nvcswch/s  Command
05:25:41 PM         4      7.84      0.00  ksoftirqd/0
05:25:41 PM         9      1.96      0.00  ksoftirqd/1
05:25:41 PM        13     10.78      0.00  ksoftirqd/2
05:25:41 PM        17     10.78      0.00  ksoftirqd/3
05:25:41 PM        19      0.98      0.00  events/0
05:25:41 PM        20      0.98      0.00  events/1
05:25:41 PM        21      0.98      0.00  events/2
05:25:41 PM        22      0.98      0.00  events/3
05:25:41 PM        29      0.98      0.00  bdi-default
05:25:41 PM        61      0.98      0.00  khugepaged
05:25:41 PM       197      0.98      0.00  mpt_poll_0
05:25:41 PM       598      0.98      0.00  vmmemctl
05:25:41 PM      1231      0.98      0.00  zabbix_agentd
05:25:41 PM      1235      0.98      0.00  zabbix_agentd
05:25:41 PM      3360     10.78      0.00  redis-server
05:25:41 PM      3748      0.98    116.67  python
05:25:41 PM      7109      2.94     78.43  bash
05:25:41 PM      7698      0.98      1.96  pidstat
05:25:41 PM     29194      0.98    313.73  apps.plugin

從pidstat的輸出能夠發現,CPU使用率的升高是因爲sysbench致使的,它的CPU使用率已經達到了100%,但上下文切換則是來自其餘進程,包括自願上下文切換頻率較高的redis-server和內核進程ksoftirqd/二、ksoftirqd/3,以及非自願上下文切換頻率比較高的python和apps.plugnin。

因爲Linux調度的最小單位是線程,而sysbench模擬的也是線程的調度問題,所以vmstat顯示的中斷次數遠大於pidstat中顯示的次數,在pidstat後面加上選項-t,對線程進行監控:以下

[root@localhost ~]# pidstat -w -t -u 1
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/29/2020     _x86_64_    (4 CPU)

06:05:28 PM      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
06:05:29 PM        13         -    0.00    0.97    0.00    0.97     2  ksoftirqd/2
06:05:29 PM         -        13    0.00    0.97    0.00    0.97     2  |__ksoftirqd/2
06:05:29 PM         -      3726    0.00    0.97    0.00    0.97     1  |__netdata
06:05:29 PM         -      3738    0.00    0.97    0.00    0.97     2  |__netdata
06:05:29 PM         -      4020    0.00    0.97    0.00    0.97     0  |__python
06:05:29 PM     10405         -   33.98  100.00    0.00  100.00     1  sysbench
06:05:29 PM         -     10406    4.85   36.89    0.00   41.75     1  |__sysbench
06:05:29 PM         -     10407    2.91   31.07    0.00   33.98     2  |__sysbench
06:05:29 PM         -     10408    2.91   33.01    0.00   35.92     2  |__sysbench
06:05:29 PM         -     10409    2.91   33.98    0.00   36.89     2  |__sysbench
06:05:29 PM         -     10410    3.88   33.98    0.00   37.86     3  |__sysbench
06:05:29 PM         -     10411    3.88   33.01    0.00   36.89     2  |__sysbench
06:05:29 PM         -     10412    1.94   31.07    0.00   33.01     2  |__sysbench
06:05:29 PM         -     10413    4.85   33.01    0.00   37.86     3  |__sysbench
06:05:29 PM         -     10414    2.91   33.01    0.00   35.92     1  |__sysbench
06:05:29 PM         -     10415    3.88   34.95    0.00   38.83     0  |__sysbench
06:05:29 PM     10428         -    0.97    1.94    0.00    2.91     0  pidstat
06:05:29 PM         -     10428    0.97    1.94    0.00    2.91     0  |__pidstat
06:05:29 PM     29194         -    0.00    0.97    0.00    0.97     2  apps.plugin
06:05:29 PM         -     29194    0.00    0.97    0.00    0.97     2  |__apps.plugin

06:05:28 PM      TGID       TID   cswch/s nvcswch/s  Command
06:05:29 PM         4         -      9.71      0.00  ksoftirqd/0
06:05:29 PM         -         4      9.71      0.00  |__ksoftirqd/0
06:05:29 PM         9         -      7.77      0.00  ksoftirqd/1
06:05:29 PM         -         9      7.77      0.00  |__ksoftirqd/1
06:05:29 PM        13         -      7.77      0.00  ksoftirqd/2
06:05:29 PM         -        13      7.77      0.00  |__ksoftirqd/2
06:05:29 PM        17         -     15.53      0.00  ksoftirqd/3
06:05:29 PM         -        17     15.53      0.00  |__ksoftirqd/3
06:05:29 PM        19         -      0.97      0.00  events/0
06:05:29 PM         -        19      0.97      0.00  |__events/0
06:05:29 PM        20         -      0.97      0.00  events/1
06:05:29 PM         -        20      0.97      0.00  |__events/1
06:05:29 PM        21         -      0.97      0.00  events/2
06:05:29 PM         -        21      0.97      0.00  |__events/2
06:05:29 PM        22         -      0.97      0.00  events/3
06:05:29 PM         -        22      0.97      0.00  |__events/3
06:05:29 PM        28         -      0.97      0.00  sync_supers
06:05:29 PM         -        28      0.97      0.00  |__sync_supers
06:05:29 PM       197         -      0.97      0.00  mpt_poll_0
06:05:29 PM         -       197      0.97      0.00  |__mpt_poll_0
06:05:29 PM       598         -      0.97      0.00  vmmemctl
06:05:29 PM         -       598      0.97      0.00  |__vmmemctl
06:05:29 PM      1202         -      0.97      0.00  master
06:05:29 PM         -      1202      0.97      0.00  |__master
06:05:29 PM      1231         -      0.97      0.00  zabbix_agentd
06:05:29 PM         -      1231      0.97      0.00  |__zabbix_agentd
06:05:29 PM      1235         -      1.94      0.00  zabbix_agentd
06:05:29 PM         -      1235      1.94      0.00  |__zabbix_agentd
06:05:29 PM      3360         -     10.68      0.00  redis-server
06:05:29 PM         -      3360     10.68      0.00  |__redis-server
06:05:29 PM         -      3725      0.97     31.07  |__netdata
06:05:29 PM         -      3726      0.97      0.00  |__netdata
06:05:29 PM         -      3727      0.97      0.00  |__netdata
06:05:29 PM         -      3728      2.91      0.00  |__netdata
06:05:29 PM         -      3729     49.51      2.91  |__netdata
06:05:29 PM         -      3730      0.97      0.00  |__netdata
06:05:29 PM         -      3733      0.97      0.00  |__netdata
06:05:29 PM         -      3738      0.97     87.38  |__netdata
06:05:29 PM         -      3740      1.94      0.00  |__netdata
06:05:29 PM         -      3743      0.97      0.00  |__netdata
06:05:29 PM         -      3744      0.97      0.00  |__netdata
06:05:29 PM         -      3745      0.97      0.00  |__netdata
06:05:29 PM         -      3751      0.97      0.00  |__netdata
06:05:29 PM      3748         -      0.97      0.00  python
06:05:29 PM         -      3748      0.97      0.00  |__python
06:05:29 PM         -      4020      3.88      6.80  |__python
06:05:29 PM         -      4021      3.88      2.91  |__python
06:05:29 PM      7109         -      0.97     52.43  bash
06:05:29 PM         -      7109      0.97     52.43  |__bash
06:05:29 PM      9337         -      1.94      0.00  showq
06:05:29 PM         -      9337      1.94      0.00  |__showq
06:05:29 PM         -     10406  18642.72  45331.07  |__sysbench
06:05:29 PM         -     10407  20953.40  42127.18  |__sysbench
06:05:29 PM         -     10408  17404.85  44594.17  |__sysbench
06:05:29 PM         -     10409  18404.85  45963.11  |__sysbench
06:05:29 PM         -     10410  12807.77  61773.79  |__sysbench
06:05:29 PM         -     10411  19445.63  38708.74  |__sysbench
06:05:29 PM         -     10412  17883.50  40695.15  |__sysbench
06:05:29 PM         -     10413  17189.32  49639.81  |__sysbench
06:05:29 PM         -     10414  18169.90  45739.81  |__sysbench
06:05:29 PM         -     10415  14832.04  47845.63  |__sysbench
06:05:29 PM     10428         -      0.97     96.12  pidstat
06:05:29 PM         -     10428      0.97     96.12  |__pidstat
06:05:29 PM         -     21200      1.94      0.00  |__grafana-server
06:05:29 PM         -     21202      0.97      0.00  |__grafana-server
06:05:29 PM         -     21206      1.94      0.00  |__grafana-server
06:05:29 PM         -     21209      0.97      0.00  |__grafana-server
06:05:29 PM         -     25021      1.94      0.00  |__grafana-server
06:05:29 PM     29194         -      0.97    150.49  apps.plugin
06:05:29 PM         -     29194      0.97    150.49  |__apps.plugin

能夠看到sysbench進程的上下文切換看起來並很少,可是sysbench的子線程的上下文切換次數卻不少,咱們發現進程的上下文切換髮生不少同時中斷次數也上升到將近2萬,具體是什麼類型的中斷上升還須要繼續進行監測。

因爲中斷髮生在內核態,而pidstat只是一個進程的性能分析工具,所以他並不能提供任何關於中斷的詳細信息。所以須要從/proc/interrupts這個只讀文件中讀取。/proc其實是Linux的一個虛擬文件系統,用於內核空間與用戶空間之間的通訊。/proc/interrupts就是這種通訊機制的一部分,提供了一個只讀的中斷使用狀況。

[root@localhost ~]# watch -d cat /proc/interrupts
[root@localhost ~]# cat /proc/interrupts 
           CPU0       CPU1       CPU2       CPU3       
  0:     117486          0          0          0   IO-APIC-edge      timer
  1:          7          0          0          1   IO-APIC-edge      i8042
  7:          0          0          0          0   IO-APIC-edge      parport0
  8:          1          0          0          0   IO-APIC-edge      rtc0
  9:          0          0          0          0   IO-APIC-fasteoi   acpi
 12:        108          1          0          0   IO-APIC-edge      i8042
 14:          0          0          0          0   IO-APIC-edge      ata_piix
 15:         13         17         19         27   IO-APIC-edge      ata_piix
 17:    3128770    3092486    3307137    3143451   IO-APIC-fasteoi   ioc0
 24:          0          0          0          0   PCI-MSI-edge      pciehp
 25:          0          0          0          0   PCI-MSI-edge      pciehp
 26:          0          0          0          0   PCI-MSI-edge      pciehp
 27:          0          0          0          0   PCI-MSI-edge      pciehp
 28:          0          0          0          0   PCI-MSI-edge      pciehp
 29:          0          0          0          0   PCI-MSI-edge      pciehp
 30:          0          0          0          0   PCI-MSI-edge      pciehp
 31:          0          0          0          0   PCI-MSI-edge      pciehp
 32:          0          0          0          0   PCI-MSI-edge      pciehp
 33:          0          0          0          0   PCI-MSI-edge      pciehp
 34:          0          0          0          0   PCI-MSI-edge      pciehp
 35:          0          0          0          0   PCI-MSI-edge      pciehp
 36:          0          0          0          0   PCI-MSI-edge      pciehp
 37:          0          0          0          0   PCI-MSI-edge      pciehp
 38:          0          0          0          0   PCI-MSI-edge      pciehp
 39:          0          0          0          0   PCI-MSI-edge      pciehp
 40:          0          0          0          0   PCI-MSI-edge      pciehp
 41:          0          0          0          0   PCI-MSI-edge      pciehp
 42:          0          0          0          0   PCI-MSI-edge      pciehp
 43:          0          0          0          0   PCI-MSI-edge      pciehp
 44:          0          0          0          0   PCI-MSI-edge      pciehp
 45:          0          0          0          0   PCI-MSI-edge      pciehp
 46:          0          0          0          0   PCI-MSI-edge      pciehp
 47:          0          0          0          0   PCI-MSI-edge      pciehp
 48:          0          0          0          0   PCI-MSI-edge      pciehp
 49:          0          0          0          0   PCI-MSI-edge      pciehp
 50:          0          0          0          0   PCI-MSI-edge      pciehp
 51:          0          0          0          0   PCI-MSI-edge      pciehp
 52:          0          0          0          0   PCI-MSI-edge      pciehp
 53:          0          0          0          0   PCI-MSI-edge      pciehp
 54:          0          0          0          0   PCI-MSI-edge      pciehp
 55:          0          0          0          0   PCI-MSI-edge      pciehp
 56:   12676123  621337444   15964441   14094017   PCI-MSI-edge      eth0-rxtx-0
 57:   12934876   27740827  549375875   13481933   PCI-MSI-edge      eth0-rxtx-1
 58:   12958840   27092299   22935606  555653407   PCI-MSI-edge      eth0-rxtx-2
 59:  533414281   24804405   22861636   20169043   PCI-MSI-edge      eth0-rxtx-3
 60:          0          0          0          0   PCI-MSI-edge      eth0-event-4
NMI:          0          0          0          0   Non-maskable interrupts
LOC: 3073899782 2932109969 2836889656 2806862212   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
PMI:          0          0          0          0   Performance monitoring interrupts
IWI:         18         16         18         15   IRQ work interrupts
RES:  486603569  505967773  471350449  492621309   Rescheduling interrupts
CAL:      75258       1646      73324       1735   Function call interrupts
TLB:   33950017   55405448   32837754   52628068   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
MCE:          0          0          0          0   Machine check exceptions
MCP:     117332     117332     117332     117332   Machine check polls
ERR:          0
MIS:          0

經過觀察發現,變化速度最快的是重調度中斷RES,這個中斷類型表示,喚醒空閒狀態的CPU來調度薪的任務運行,這是多處理器系統中,調度器用來分散任務導不一樣CPU的機制,一般也被稱爲處理器間中斷

因此,這裏的中斷升高仍是由於過多任務的調度問題,跟前面上下文切換次數的分析結果是一致的。

上下文切換正常的數值取決於系統自己的CPU性能。若是系統的上下文切換次數比較穩定,那麼從數百到1萬之內,都應該算是正常。當上下文切換次數超過一萬次,或者切換次數出現數量級的增加時,就頗有可能出現了性能問題。

這個時候須要依據上下文切換的類型,在作具體分析:

  • 自願上下文切換變多了,說明進程都在等待自願,有可能發生了IO等其餘問題;

  • 非自願上下文切換變多了,說明進程都在被強制調度,也就是都在爭搶CPU,說明CPU的確成了瓶頸;

  • 中斷次數變多了,說明CPU被中斷處理程序佔用了,還須要經過查看/proc/interrupts文件來分析具體的中斷類型

CPU性能分析優化

CPU使用率

Linux做爲一個多任務操做系統,將每一個CPU的時間劃分爲很短的時間片,再經過調度器輪流分配給各個任務使用,所以形成多任務同時運行的錯覺。

爲了維護CPU時間,Linux經過事先定義的節拍率(內核中表示爲HZ),觸發時間中斷,並使用全局變量Jiffies記錄了開機以來的節拍數。每發生一次時間中斷,Jiffies的值就加1。

節拍率HZ是內核的可配選項,能夠配置爲100、250、1000等。不一樣的系統可能設置不一樣的數值,能夠經過查詢/boot/config內核選項來查看它的配置(CONFIG_HZ=1000)。好比在個人服務器系統中,節拍率設置成了1000,也就是每秒鐘觸發1000次時間中斷。

[root@localhost ~]# grep 'CONFIG_HZ=' /boot/config-2.6.32-431.el6.x86_64 
CONFIG_HZ=1000

正由於節拍率HZ是內核選項,因此用戶空間程序並不能直接訪問。爲了方便用戶空間程序,內核還提供了一個用戶空間節拍率USER_HZ,它老是固定爲100,也就是1/100秒。這樣,用戶空間程序並不須要關心內核中HZ被設置成了多少,由於它看到的老是固定值USER_HZ。

Linux經過/proc虛擬文件系統,向用戶空間提供了系統內部狀態的信息,而/proc/stat提供的就是系統的CPU和任務統計信息。若是隻須要關注CPU,能夠執行以下命令:

[root@localhost ~]# cat /proc/stat |grep ^cpu
cpu  182993898 729 117810616 13772680802 1631791 13585 2713967 0 0
cpu0 44712915 43 27980485 3442961333 378691 3216 649777 0 0
cpu1 45582701 297 30219438 3442511274 419280 3848 738211 0 0
cpu2 46830450 48 28005111 3445732783 420358 3273 676506 0 0
cpu3 45867831 339 31605580 3441475411 413462 3246 649470 0 0

這裏輸出結果是一個表格。其中,第一列表示的是CPU編號,如cpu0、cpu一、cpu二、cpu3,而第一行沒有編號的cpu,表示的是全部CPU的累加。而其餘列表示不一樣場景下CPU的累加節拍數,她的單位是USER_HZ,也就是10ms(1/100秒),因此這其實就是不一樣場景下的CPU時間。

  • user(一般縮寫爲us),表明用戶態CPU時間。注意,它不包含下面的nice時間,但包括了gust時間。

  • nice(一般縮寫爲ni),表明低級優先級用戶態CPU時間,也就是進程的nice值被調整爲1-19之間的CPU時間,這裏注意nice可取值範圍是-20到19,數值越大,優先級反而越低。

  • system(一般縮寫爲sys),表明內核態CPU時間。

  • idle(一般縮寫爲id),表明空閒時間。注意,它不包括等待IO的時間(iowait)。

  • iowait(一般縮寫爲wa),表明等待IO的CPU時間。

  • irq(一般縮寫爲hi),表明處理硬中斷的CPU時間。

  • softirq(一般縮寫爲si),表明處理軟中斷的CPU時間。

  • steal(一般縮寫爲st),表明當系統運行在虛擬機中的時候,被其餘虛擬機佔用的CPU時間。

  • guest(一般縮寫爲guest),表明經過虛擬化運行其餘操做系統的時間,也就是運行虛擬機的CPU時間、

  • guest_nice(一般縮寫爲gnice),表明低優先級運行虛擬機的時間。

一般所說的CPU使用率,就是除了空閒時間外的其餘時間佔用CPU時間的百分比,用公式表示就是

根據這個公式,咱們就能夠從/proc/stat中的數據,很容易地計算出CPU使用率。固然,也能夠用每個場景的CPU時間,除以總的CPU時間,計算出每一個場景的CPU使用率。

查看/proc/stat中的數據,顯示的是開機以來的節拍數累加值,因此直接算出來的,是開機以來的平均CPU使用率,通常沒有什麼參考價值。

事實上,爲了計算CPU使用率,性能工具通常都會間隔一段時間的兩次值,做差後,再計算出這段時間內平均CPU使用率。

這個公式,就是咱們用各類性能工具所看到的CPU使用率的實際計算方法。

進程的CPU使用率方法與系統指標相似,Linux也給每一個進程提供了運行狀況的統計信息,也就是/proc/[pid]/stat。不過,這個文件包含的數據就比較豐富了,總共有52列的數據。

性能分析工具給出的都是間隔一段時間的平均CPU使用率,因此要注意間隔時間的設置,特別是用多個工具對比分析時,你必定要保證他們用的是相同的間隔時間。

好比,對比一下top和ps這兩個工具報告的CPU使用率,默認的結果極可能不同,由於top默認使用3秒時間間隔,而ps使用的倒是進程的整個生命週期。

查看CPU使用率

top和ps是最經常使用的性能分析工具:

  • top顯示了系統整體的CPU和內存使用狀況,以及各個進程的資源使用狀況。

  • ps則只顯示了每一個進程的資源使用狀況。

關於top命令使用見下圖詳解

top命令每一個進程都有一個%CPU列,表示進程的CPU使用率。它是用戶態和內核態CPU使用率的總和,包括進程用戶空間使用的CPU、經過系統調用執行的內核空間CPU、以及在就緒隊列等待運行的CPU。在虛擬化環境中,它還包括了運行虛擬機佔用的CPU,能夠發現top命令並無細分進程的用戶態CPU和內核態CPU。

若是想要查看進程CPU使用率的具體狀況須要使用pidstat命令來進行觀測;

[root@localhost ~]# pidstat 1 5
Linux 2.6.32-431.el6.x86_64 (localhost.localdomain)     04/30/2020     _x86_64_    (4 CPU)

02:29:12 PM       PID    %usr %system  %guest    %CPU   CPU  Command
02:29:13 PM     14734    0.00    0.98    0.00    0.98     3  apps.plugin
02:29:13 PM     29918    0.98    0.98    0.00    1.96     1  pidstat

02:29:13 PM       PID    %usr %system  %guest    %CPU   CPU  Command
02:29:14 PM      3360    0.00    1.00    0.00    1.00     0  redis-server
02:29:14 PM      3723    1.00    0.00    0.00    1.00     0  netdata
02:29:14 PM     14734    1.00    0.00    0.00    1.00     3  apps.plugin
02:29:14 PM     21198    1.00    0.00    0.00    1.00     1  grafana-server
02:29:14 PM     29167    0.00    1.00    0.00    1.00     2  bash
02:29:14 PM     29918    0.00    1.00    0.00    1.00     1  pidstat

02:29:14 PM       PID    %usr %system  %guest    %CPU   CPU  Command
02:29:15 PM      3748    1.00    0.00    0.00    1.00     0  python
02:29:15 PM     14734    0.00    1.00    0.00    1.00     3  apps.plugin
02:29:15 PM     29918    0.00    1.00    0.00    1.00     1  pidstat

02:29:15 PM       PID    %usr %system  %guest    %CPU   CPU  Command
02:29:16 PM      3723    1.00    0.00    0.00    1.00     0  netdata
02:29:16 PM     14734    0.00    1.00    0.00    1.00     3  apps.plugin
02:29:16 PM     21198    0.00    1.00    0.00    1.00     1  grafana-server
02:29:16 PM     29167    1.00    0.00    0.00    1.00     1  bash
02:29:16 PM     29918    1.00    0.00    0.00    1.00     1  pidstat

02:29:16 PM       PID    %usr %system  %guest    %CPU   CPU  Command
02:29:17 PM      3360    1.00    0.00    0.00    1.00     0  redis-server
02:29:17 PM      3723    1.00    1.00    0.00    2.00     0  netdata
02:29:17 PM     14734    1.00    0.00    0.00    1.00     3  apps.plugin
02:29:17 PM     29918    0.00    1.00    0.00    1.00     1  pidstat

Average:          PID    %usr %system  %guest    %CPU   CPU  Command
Average:         3360    0.20    0.20    0.00    0.40     -  redis-server
Average:         3723    0.60    0.20    0.00    0.80     -  netdata
Average:         3748    0.20    0.00    0.00    0.20     -  python
Average:        14734    0.40    0.60    0.00    1.00     -  apps.plugin
Average:        21198    0.20    0.20    0.00    0.40     -  grafana-server
Average:        29167    0.20    0.20    0.00    0.40     -  bash
Average:        29918    0.40    0.80    0.00    1.20     -  pidstat

如上面的pidstat命令,就間隔1秒展現了進程的5組CPU使用率,包括

  • 用戶態CPU使用率(%usr)

  • 內核態CPU使用率(%system);

  • 運行虛擬機CPU使用率(%guest);

  • 等待CPU使用率(%wait);

  • 以及總的CPU使用率(%CPU)

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

CPU使用率分析

perf是Linux2.6.31之後內置的性能分析工具,它以性能時間採樣爲基礎,不只能夠分析系統的各類事件和內核性能,還能夠用來分析指定應用程序的性能問題。

[root@localhost ~]# perf top
    Samples:  11K  of event 'cpu-clock', Event count (approx.):1015
    Overhead  Shared Object        Symbol
     9.42%  [kernel]            [k] kallsyms_expand_symbol
     7.03%  perf                [.] symbols__insert
     6.37%  perf                [.] rb_next
     4.51%  [kernel]            [k] vsnprintf
     4.11%  [kernel]            [k] format_decode
     3.71%  [kernel]            [k] number
     3.45%  [kernel]            [k] strnlen
     2.79%  [kernel]            [k] string
     2.52%  perf                [.] hex2u64
     2.12%  libc-2.14.so        [.] __strcmp_sse42
     1.99%  libc-2.14.so        [.] __memcpy_sse2
     1.86%  libc-2.14.so        [.] _int_malloc
     1.59%  libc-2.14.so        [.] _IO_getdelim
     1.59%  libc-2.14.so        [.] __strchr_sse42
     1.46%  libc-2.14.so        [.] __libc_calloc
     1.33%  libc-2.14.so        [.] __strstr_sse42
     1.19%  [kernel]            [k] get_task_cred
     1.19%  [kernel]            [k] update_iter
     1.06%  [kernel]            [k] module_get_kallsym
     1.06%  libpthread-2.14.so  [.] pthread_rwlock_rdlock

輸出結果中,第一行包含三個數據,分別是採樣數(Sample)、事件類型(event)和事件總數量(Event count)。例子中,pref總共採集了11K個CPU時鐘事件,須要注意若是採樣數過少,那下面的排序和百分比就沒什麼實際參考價值。

  • 第一列Overhead,是該符號的性能事情在全部採用中的比例,用百分比來表示。

  • 第二列Shared,是該函數或指令所在的動態共享對象,如內核、進程名、動態連接庫名、內核模塊名等。

  • 第三列Object,是動態共享對象的類型。好比[.]表示用戶空間的可執行程序、或者動態連接庫,而[k]則表示內核空間。

  • 最後一列Symbol是符號名,也就是函數名。當函數名未知時,用十六進制的地址來表示。

從上面數據,能夠看到,佔用CPU時鐘最多的是kernel(內核),不過它的比例也只有9.42%,說明系統並無CPU性能問題。

系統進程分析

進程狀態

參考ps命令詳解,這裏再也不多說

相關文章
相關標籤/搜索