軟體性能測試(連載6)
- 2020 年 2 月 19 日
- 筆記
2.2 Linux的性能監控
本節以Ubuntu Linux為例進行介紹。
1. CPU
1)uptime命令
#uptime
08:26am up 7 min, 2 users, load average: 0.17, 0.16, 0.12
•08:26am。
當前時間是08:26am。
•up 7 min。
已經啟動了7分鐘。
•2 users。
當前有2個用戶登錄。
•load average:0.17, 0.16, 0.12。
最近1分鐘、5分鐘和15分鐘的平均負載為0.17、0.16和0.12。
負載為1表示當前單核CPU全部佔用,如果一台機器有3個CPU,每個CPU都是雙核的,這是負載最大值為1×2×3=6。如果5分鐘以及15分鐘的負載指標的大於CPU個數×CPU核數×0.7,並且長時間比較高,說明CPU不夠用。
•總核數 = 物理CPU個數×每顆物理CPU的核數。
•總邏輯CPU數 = 物理CPU個數×每顆物理CPU的核數×超執行緒數。
通過以下命令可以查看CPU個數、每個物理CPU中core的核數、邏輯CPU的個數和CPU資訊(型號)。
•查看物理CPU個數。
#cat /proc/cpuinfo| grep "physical id"|sort| uniq| wc -l
2
2•查看每個物理CPU中core的核數。
#cat /proc/cpuinfo| grep "cpu cores"|uniq
cpu cores: 2
•查看邏輯CPU的個數。
#cat /proc/cpuinfo| grep "processor"| wc-l
4
4•查看CPU資訊(型號)。
#cat /proc/cpuinfo | grep name | cut -f2 -d: |uniq -c
4 Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
案例3-11:CPU負載分析
•Load average: 0.5,0.5,0.5。
表示最近15分鐘內CPU負載沒有變化。
•Load average: 0.5,2,5。
表示最近15分鐘內CPU負載逐漸變小。
•Load average: 5,2,0.5。
表示最近15分鐘內CPU負載逐漸變大。
2)top命令
#top
top – 18:00:48 up 4 min, 1 user, load average: 0.88, 0.57, 0.26
Tasks: 343 total, 1 running, 229 sleeping, 0stopped, 0 zombie
%Cpu(s): 2.6 us, 4.2 sy, 0.0 ni, 93.1 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 4312632 total, 1931028 free, 1392792 used, 988812 buff/cache
KiB Swap: 969960 total, 969960 free, 0 used. 2657976 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2179 jerry 20 0 3647552 177412 79692 S 14.2 4.1 0:10.86 gnome-shell
2049 jerry 20 0 474988 101148 47332 S 6.0 2.3 0:04.23
2531 jerry 20 0 800760 37440 27580 S 2.3 0.9 0:01.31 gnome-terminal-
2013 _apt 20 0 88940 8816 7840 S 1.7 0.2 0:02.26 http
…
可以按下鍵盤上的【1】鍵切換到顯示各顆CPU的狀態。
top – 18:32:05 up 29 min, 1 user, load average: 0.91, 0.35, 0.13
Tasks: 304 total, 1 running, 225 sleeping, 0stopped, 0 zombie
%Cpu0 : 2.0 us, 3.7 sy, 0.0 ni, 94.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.7 us, 0.7 sy, 0.0 ni, 98.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.3 us, 0.3 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.3 us, 2.0 sy, 0.0 ni, 97.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
這裡的CPU顆數為4。可以看出第一行的內容就是uptime命令的內容。
top – 18:00:48 up 4 min, 1 user, load average: 0.88, 0.57, 0.26
表示當前時間為18:00:48,持續運行了4分鐘,當前有1個用戶登錄,最近1分鐘、5分鐘和15分鐘的平均負載為0.88,0.57和0.26。
top命令第二行顯示的是各個CPU狀態的進程數。
Tasks: 343 total, 1 running, 229 sleeping, 0stopped, 0 zombie
上面顯示結果表示當前共有現在共有343個進程,1個處於運行狀態,229個處於睡眠狀態,停止狀態和殭屍狀態的進程都為0。對於各個狀態,如表3-4所示。
表3-4 CPU狀態
標號 |
中文名 |
英文名 |
解釋 |
---|---|---|---|
D |
不可中斷的睡眠態 |
uninterruptible sleep |
進程正在跟硬體交互,並且交互過程不允許被其他進程或中斷打斷。通常出現在I/O阻塞 |
R |
運行態 |
running or runnable |
表示進程在 CPU 的就緒隊列中,正在運行或者正在等待運行。 |
S |
可中斷的睡眠態 |
Interruptible sleep |
進程因為等待某個事件而被系統掛起。當進程等待的事件發生時,它會被喚醒並進入 R 狀態。 |
T |
被跟蹤或已停止 |
stooped |
表示進程處於暫停或者跟蹤狀態(命令行調試) |
Z |
殭屍態 |
zombie |
進程實際上已經結束了,但是父進程還沒有回收它的資源(比如進程的描述符、PID 等)。 |
I |
空閑狀態 |
Idle |
也就是空閑狀態,用在不可中斷睡眠的內核執行緒上。D 狀態的進程會導致平均負載升高, I 狀態的進程卻不會。 |
X |
死亡狀態 |
dead |
用Top、PS命令獲取不到 |
top命令第三行表示CPU概覽:%Cpu(s)表示CPU使用百分比,按照時間佔用計算,單位s。其含義如表3-5所示。
表3-5 CPU概覽
標記 |
縮寫 |
含義 |
---|---|---|
user |
%us |
代表用戶態 CPU 時間。注意,它不包括下面的 nice 時間,但包括了 guest 時間。 |
system |
%sy |
代表內核態 CPU 時間。 |
nice |
%ni |
代表低優先順序用戶態 CPU 時間,也就是進程的 nice 值被調整為 1-19 之間時的 CPU 時間。這裡注意,nice 可取值範圍是 -20 到 19,數值越大,優先順序反而越低。 |
idle |
%id |
代表空閑時間。注意,它不包括等待 I/O 的時間(iowait)。 |
iowait |
%wa |
代表等待 I/O 的 CPU 時間。 |
irq |
%hi |
代表處理硬中斷的 CPU 時間。 |
softirq |
%si |
代表處理軟中斷的 CPU 時間。 |
steal |
%st |
虛擬 CPU 等待實際 CPU 的時間的百分比 |
guest |
|
代表通過虛擬化運行其他作業系統的時間,也就是運行虛擬機的 CPU 時間。 |
guest_nice |
gnice |
代表以低優先順序運行虛擬機的時間。 |
%Cpu(s): 2.6 us, 4.2 sy, 0.0 ni, 93.1 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
上面顯示結果表示2.6%佔有用戶態 CPU 時間、4.2%佔有內核態 CPU 時間,93.1%是空閑時間,處理軟中斷的佔0.2%。
3)平均負載和CPU使用率
CPU 使用率,是單位時間內CPU繁忙情況的統計,和平均負載並不一定完全對應。
•CPU 密集型進程。
使用大量CPU會導致平均負載升高,平均負載和CPU使用率是一致的。
•I/O 密集型進程。
等待I/O也會導致平均負載升高,但CPU使用率不一定很高。
平均負載是指單位時間內,系統處於可運行狀態的R狀態進程數+不可中斷狀態的D 狀態(Disk Sleep)進程數之。而處於可運行狀態R狀態的進程又包括正在使用 CPU進程和正在等待CPU的進程,不可中斷狀態的D 狀態(Disk Sleep)進程即正處於等待I/O的進程。
4)不可中斷的睡眠態進程
不可中斷的睡眠態的進程一般均為在運行過程中需要I/O提供數據。處於等待I/O狀態的進程,由於這種是不可被打斷的並且又處於睡眠態,所以叫做不可中斷的睡眠態。如果系統中不可中斷的睡眠態的進程比較多,可以確認系統在I/O上遇到了瓶頸。而這些I/O往往是磁碟I/O。由於與磁碟讀寫有關係,建議使用dstat 命令(同時看見CPU與I/O資訊)來分析。
#dstat 10 1
You did not select any stats, using -cdngy bydefault.
–total-cpu-usage– -dsk/total- -net/total—-paging– —system–
usr sys idl wai stl| read writ | recv send | in out | int csw
1 1 99 0 0 | 9232k 470k| 0 0 | 0 0 | 129 192
從上面可以看見有9232K的數據處於磁碟讀操作,性能低的瓶頸可能有進程在讀磁碟。
一般而言直接讀寫磁碟,對 I/O 敏感型應用(比如資料庫系統)是很友好的,因為可以在應用中,直接控制磁碟的讀寫。但在這種情況是非常消耗CPU資源的,最好還是通過系統快取來優化磁碟 I/O的讀寫,換句話說,刪除O_DIRECT 這個選項就可以了。下面程式碼就是直接讀寫磁碟。
open(disk, O_RDONLY|O_DIRECT|O_LARGEFILE, 0755)
5)殭屍進程
現在來介紹一下殭屍進程,殭屍進程是由於父進程建立子進程以後沒有及時回收造成的。看一下正常父進程創建子進程,子進程結束後父進程收回的流程。
(1)父進程創建子進程。
(2)父進程調用wait()或者waitpid()等待子進程結束。
(3)子進程結束向父進程發送SIGCHLD 訊號。
(4)父進程收到SIGCHLD 訊號後註冊SIGCHLD訊號的處理函數。
(5)父進程非同步回收子進程的資源。
如果父進程在創建子進程後沒有調用wait()或者waitpid()等待子進程結束或者子進程結束後沒有給父進程發SIGCHLD 訊號就造成殭屍進程,如下程式碼。
int status = 0;
for (;;) {
for (intsign = 0; sign < 5; sign ++) {
if(f()==0) {
sub_process();
}
}
sleep(3);
}
while(wait(&status)>0);
這段程式碼while語句放在了循環外面,這樣wait()方法沒有時機被調用,所以容易產生殭屍進程。在調試的時候可以使用pstree-aps <PID> 查看<PID>下的所有子進程(其中參數a表示輸出命令行選項、p表示PID以及s表示指定進程的父進程)。
#pstree -aps 3785
systemd,1 auto noprompt
└─systemd,1894 –user
└─gnome-terminal-,2416
└─bash,3772
└─bash,3782
└─python3,3783 manage.py runserver 0.0.0.0:8000 –insecure
└─python3,3785 manage.py runserver 0.0.0.0:8000 –insecure
└─{python3},3787