一個系統或者網站在功能開發完成后一般最終都需要部署到服務器上運行,那么服務器的性能監控和分析就顯得非常重要了,選用什么配置的服務器、如何對服務器進行調優、如何從服務器監控中發現程序的性能問題、如何判斷服務器的瓶頸在哪里等 就成為了服務器性能監控和分析時重點需要去解決的問題了。
本文章節目錄:
1 服務器的性能監控和分析
1.1、 Linux服務器的性能指標監控和分析
1.1.1 、 通過vmstat深挖服務器的性能問題
1.1.2 、 如何通過mpstat 分析服務器的性能指標
1.1.3 、 從lsof中能看到什么
1.1.4 、 如何通過free看懂內存的真實使用
1.1.5、 網絡流量如何監控
1.1.6 、 nmon對Linux服務器的整體性能監控
1.1.7 、 如何通過top發現問題
1.1.8、 如何通過pidstat發現性能問題
1.2 、 Windows服務器的性能指標監控和分析
1.2.1、 Windows性能監視器
1.2.2、 Windows性能監視器下的性能分析
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。
1.1 、 Linux服務器的性能指標監控和分析
1.1.1 、通過vmstat深挖服務器的性能問題
vmstat差不多是性能測試時在linux服務器上執行最多的命令,使用該命令往往能輔助我們進行很多的性能問題定位。
我們先來看一下執行vmstat 命令后,獲取到的服務器的資源使用的監控數據有哪些。
我們在執行vmstat 的時候,后面加了兩個參數,其中參數1代表每隔1秒獲取一次服務器的資源使用數據,10代表總共獲取10次。
指標 |
含義 |
r |
r是第一列的監控數據,代表了目前實際在運行的指令隊列(也就是有多少任務需要CPU來進行執行),從數據來看,這台服務器目前CPU的資源比較空閑,如果發現這個數據超過了服務器CPU的核數,就可能會出現CPU瓶頸了(在判斷時,還需要結合CPU使用的百分比一起來看,也就是上圖中最后5列的數據指標),一般該數據超出了CPU核數的3個時,就比較高了,超出了5個就很高了,如果都已經超過了10時,那就很不正常了,服務器的狀態就很危險了。如果運行隊列超過CPU核數過多,表示CPU很繁忙,通常會造成CPU的使用率很高。 |
b |
b是第二列的監控數據,表示目前因為等待資源而阻塞運行的指令個數,比如因為等待I/O、內存交換、CPU等資源而造成了阻塞,該值如果過高了的話,就需要檢查服務器上I/O、內存,CPU等資源是不是出現了瓶頸。 |
swpd |
swpd是第三列的監控數據,表示虛擬內存(swap)已使用的大小(swap指的是服務器的物理運行內存不夠用的時候,會把物理內存中的部分空間釋放出來,以供需要運行的程序去使用,而那些釋放出來的空間可能來自一些很長時間沒有什么操作的程序,這些被釋放的空間會被臨時保存到Swap中,等到那些程序要運行時,再從Swap分區中恢復保存的數據到內存中,swap分區一般使用的都是磁盤的空間,磁盤的I/O讀寫一般會比物理內存慢很多,如果存在大量的swap讀寫交換,將會非常影響程序運行的性能),也就是切換到內存交換區的內存數量(單位為k),此處需要注意,並不是swpd的值大於0,就是服務器的物理內存已經不夠用了,通常還需要結合si和so這兩個數據指標來一起分析,如果si和so 還維持在0左右,那服務器的物理內存還是夠用的。 |
free |
free是第四列的監控數據,表示空閑的物理內存的大小,就是還有多少物理內存沒有被使用(單位為k),這個free的數據是不包含buff和cache這兩列的數據值在內的。 |
buff |
buff 是第五列的監控數據,表示作為Linux/Unix系統的緩存的內存大小(單位為k),一般對塊設備的讀寫才需要緩沖,一般內存很大的服務器,這個值一般都會比較大,操作系統也會自動根據服務器的物理內存去調整緩沖區的內存使用大小,以提高讀寫的速度。 |
cache |
cache是第6列的監控數據,表示用來給已經打開的文件做緩沖的內存大小,cache直接用來記憶我們打開的文件,把空閑的物理內存的一部分拿來做文件和目錄的緩存,是為了提高程序執行的性能,當程序使用內存時,buffer/cached會很快地被使用,當空閑的物理內存不足時(即free的內存不足),這些緩存的內存便可以釋放出來。 |
si |
si是第7列的監控數據,表示每秒從磁盤(虛擬內存swap)讀入到內存的大小,如果這個值長期大於0,那物理運行內存可能已經是不夠用了。 |
so |
so是第8列的監控數據,表示每秒寫入磁盤(虛擬內存swap)的內存大小,so剛好和si相反,si一般是將磁盤空間調入內存,so一般是將內存數據調入磁盤。 |
bi |
bi是第9列的監控數據,表示塊設備每秒讀取的塊數量(從磁盤讀取數據,這個值一般表示每秒讀取了磁盤的多少個block),這里的塊設備(block)是指系統上所有的磁盤和其他塊設備,默認塊大小是1024byte。 |
bo |
bo是第10列的監控數據,表示塊設備每秒寫入的塊數量(往磁盤寫入數據,這個值一般表示每秒有多少個block寫入了磁盤)。通常情況下,隨機磁盤讀寫的時候,bi和bo這2個值越大(如超出1024k),能看到CPU在IO等待的值也會越大。 |
in |
in是第11列的監控數據,表示 每秒CPU的中斷次數,包括時鍾中斷。 |
cs |
cs是第12列的監控數據,表示 CPU每秒上下文切換次數,例如我們調用系統函數,就要進行上下文切換,線程的切換,也要進程上下文切換,這個值要越小越好,太大了,要考慮調低線程或者進程的數目,例如在apache和nginx這種web服務器中,我們一般做性能測試時會進行幾千並發甚至幾萬並發的測試,選擇web服務器的進程可以由進程或者線程的峰值一直下調,壓測,直到cs到一個比較小的值,這個進程和線程數就是比較合適的值了。系統調用也是,每次調用系統函數,我們的代碼就會進入內核空間,導致上下文切換,這個是很耗資源,也要盡量避免頻繁調用系統函數。上下文切換次數過多表示你的CPU大部分浪費在上下文切換,導致CPU干正經事的時間少了,CPU沒有充分利用,是不可取的。系統運行時,如果觀察到in和cs 這兩個指標非常高,那就需要對系統進行性能調優了。 |
us |
us(user time)是第13列的監控數據,表示用戶模式CPU使用時間的百分比,該值一般越高,說明CPU被正常利用的越好,筆者曾經在給一個機器學習算法(密集型CPU應用)做壓力測試時,us的值可以接近100,那說明CPU已經充分被算法服務使用了。 |
sy |
sy是第14列的監控數據,表示系統內核進程執行時間百分比(system time),sy的值高時,說明系統內核消耗的CPU資源多,這並不是一個服務器性能好的表現,通常in、cs、io的頻繁操作等過高,都會引起sy的指標過高,這個時候我們應該要去定位原因了。 |
id |
id是第15列的監控數據,表示空閑 CPU時間的占比,一般來說,id + us + sy = 100,一般可以認為id是空閑CPU使用率,us是用戶CPU使用率,sy是系統CPU使用率。 |
wa |
wa是第16列的監控數據,表示I/O等待時間百分比,wa的值高時,說明IO等待比較嚴重,這可能由於磁盤大量作隨機訪問造成,也有可能磁盤出現瓶頸(塊操作) |
st |
st是第17列的監控數據,表示CPU等待虛擬機調度的時間占比,這個指標一般在虛擬機中才會有,物理機中,該值一般維持為0,我們都知道虛擬機中的CPU一般是物理機CPU的虛擬核,一台物理機一般會有多個虛擬機同時在運行,那么此時虛擬機之間就會存在CPU的爭搶情況,比如某台虛擬機上運行着占用CPU很高的密集型計算,就會導致其他的虛擬機上的CPU需要一直等待密集型計算的虛擬機上CPU的釋放,st就是等待時間占CPU時間的占比,該值如果一直持續很高,那么表示虛擬服務器需要長期等待CPU,運行在該服務器的應用程序的性能會受到直接的影響,筆者曾經在壓測時發現,該值越高,也會引起sy的值變高(因為操作系統內核需要不斷的去調度CPU)。 |
vmstat還可以支持其他的參數使用,我們可以通過執行vmstat --help 命令查看到它支持的其他參數
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
l -a, --active 顯示活躍和非活躍的內存
l -f, --forks 顯示操作系統從啟動至今的fork數量,fork一般指的就是啟動過的進程數量,linux操作系統用fork()函數來創建進程。
l -m, --slabs 顯示slab的相關信息,slab是linux內核中按照對象大小進行分配的內存分配器,通過slab的信息可以來查看各個內核模塊占用的內存空間,可以通過cat /proc/meminfo |grep Slab 命令查看Slab占用的總內存大小,如果占用的內存過大,那么可能是內核模塊出現了內存泄漏了。
l -n, --one-header 這個參數表示只顯示頭部第一行的信息
l -s, --stats event counter statistics 顯示內存相關的統計信息及多種系統操作活動發生數量統計,比如CPU時鍾中斷的次數,CPU上下文切換的次數等。
l -d, --disk disk statistics 顯示每一塊磁盤I/O相關的明細信息
l -D, --disk-sum 顯示磁盤I/O相關的匯總信息,-D 顯示的信息是對-d參數顯示的每個磁盤塊的信息的匯總。
l -p, --partition <dev> partition specific statistics 顯示磁盤中某個分區的I/O讀寫信息。例如執行vmstat -p /dev/sda1 可以顯示/dev/sda1這個分區的I/O讀寫的相關的信息。
l -S, --unit <char> define display unit 使用指定單位顯示。參數有 k 、K 、m 、M ,分別代表1000、1024、1000000、1048576字節(byte)。默認單位為K(1024 bytes)
l -w, --wide wide output 這個參數用於調整命令輸出結果的顯示方式,輸出的結果和單獨執行vmstat命令得到的結果是完全一樣,只是在輸出時,會以更寬的寬度來展示數據。
l -t, --timestamp show timestamp 在vmstat命令輸出的數據的基礎上,增加每次獲取數據時的當前時間戳的輸出顯示
l -V, --version output version information and exit 輸出vmstat命令得版本信息
1.1.2、 如何通過mpstat 分析服務器的性能指標
linux中的mpstat 命令也是在性能測試時經常用來監控服務器整體性能指標的一種方式,mpstat命令和上面我們講到的vmstat命令非常類似,我們來看一下執行vmstat 命令后,獲取到的服務器的資源使用的監控數據。
我們在執行mpstat的時候,后面同樣加了兩個參數,其中參數1代表每隔1秒獲取一次服務器的資源使用數據,10代表總共獲取10次,這點和vmstat的使用很類似。
l %usr 表示的是用戶模式下CPU使用時間的百分比,和vmstat中得到的us數據基本一致
l %nice 表示CPU在進程優先級調度下CPU占用時間的百分比,在操作系統中,進程的運行是可以設置優先級的,linux操作系統也是一樣,優先級越高的,獲取到CPU運行的機會越高。這個值一般的時候都會是0.00,但是一旦我們在程序運行時,修改過默認優先級時,%nice就會產生占用時間的百分比,在linux中,執行top或者ps命令時,通常會輸出PRI/PR、NI、%ni/%nice這三個指標。
- PRI:表示進程執行的優先級,值越小,優先級就越高,會越早獲得CPU的執行權。
- NI:表示進程的Nice值,表示進程可被執行的優先級的修正數值,PRI值越小會越早被CPU執行,在加入Nice值后,將會使得PRI的值發生變化,新的PRI值=老的PRI值+Nice值,那么可以看出PRI的排序是和Nice密切相關的,Nice值越小,那么PRI值就會越小,就會越早被CPU執行,在Linux操作系統中如果Nice值相同時進程uid為root進程的執行優先級會更高。通常情況下,子進程會繼承父進程的Nice值,在操作系統啟動時init進程會被賦予0,其它進程(其它的進程基本都是init進程開辟的子進程)會自動繼承這個Nice值。
- %ni/%nice:可以形象的表示為改變過優先級的進程的占用CPU的百分比,即可以理解為Nice值影響了內核分配給進程的cpu時間片的多少。
l %sys表示系統內核進程執行時間百分比(system time),該值越高時,說明系統內核消耗的CPU資源越多,和vmstat命令中的sy數據基本一致。
l %iowait表示I/O等待時間百分比,該值越高時,說明IO等待越嚴重,和vmstat命令中的wa數據基本一致。
l %irq表示用於處理系統中斷的 CPU 百分比,和vmstat命令中的in數據的含義類似,in越高,那么%irq也會越高。
l %soft表示用於軟件中斷的 CPU 百分比。
l %steal 表示CPU等待虛擬機調度的時間占比,這個指標一般在虛擬機中才會有,物理機中該值一般維持為0,和vmstat命令中的st數據基本一致。
l %guest表示運行vCPU(虛擬處理器)時所消耗的cpu時間百分比
l %gnice表示運行降級虛擬程序所使用的CPU占比
l %idle表示空閑 CPU時間的占比,和vmstat命令中的id數據基本一致。
我們上面通過執行mpstat 1 10 獲取到的是服務器中所有的CPU核數的匯總數據,所以可以看到在顯示時,CPU列顯示的為all,如果我們需要查看服務器中么某一個CPU核的資源使用情況,可以在執行mpstat命令時,加上-P 這個參數,比如執行mpstat -P 0 1 10 命令可以獲取到服務器中CPU核編號為0的CPU核的資源的使用情況(CPU核的編號是從0開始,比如圖中我們的服務器有2個CPU核那么CPU核的編號就是0和1)。
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
1.1.3 、 從lsof中能看到什么
lsof 是對Linux操作系統中對文件進行監控的一個常用命令,使用該命令可以列出當前系統打開了哪些文件,系統中某個進程打開了哪些文件等。
我們直接執行lsof即可以顯示當前操作系統打開了哪些文件,lsof命令必須運行在root用戶下,這是因為lsof命令執行時需要訪問核心內存和內核文件,如下圖所示,我們直接執行lsof命令后得到的結果。
l 第1列展示的為進程的名稱,圖中顯示的進程名稱為nginx。
l 第2列展示的為進程的id編號(也就是Linux操作系統中常說的PID)
l 第3列展示的為進程的所有者,也就是這個進程是運行在哪個Linux用戶下的,可以看到圖中的進程基本都是運行在root用戶下,這是因為我在啟動nginx時,就是在root用戶下來啟動的
l 第4列展示的為文件描述符(File Descriptor number),常見的類型如下
文件描述符簡稱 |
英文全稱 |
中文解釋 |
cwd |
current working directory |
當前工作的目錄 |
mem |
memory-mapped file |
代表把磁盤文件映射到內存中 |
txt |
program text |
進程運行的程序文件,包括編譯后的代碼文件以及產生的數據文件等,圖中的nginx命令文件就屬於txt類型。 |
rtd |
root directory |
代表root目錄 |
pd |
parent directory |
父目錄 |
DEL |
a Linux map file that has been deleted |
代表已經刪除的Linux映射文件 |
數字+字符,如0u、1w、2w等 |
|
0:表示標准輸出 1:表示標准輸入 2:表示標准錯誤 u:表示該文件被打開並處於讀取/寫入模式 r:表示該文件被打開並處於只讀模式 w:表示該文件被打開並處於只寫入模式 |
l 第5列展示的為打開的文件類型,常見的類型如下
類型 |
英文全稱 |
解釋 |
DIR |
directory |
代表了一個文件目錄 |
CHR |
character special file |
特殊字符文件 |
LINK |
symbolic link file |
鏈接文件 |
IPv4 |
IPv4 socket |
IPv4 套接字文件 |
IPv6 |
IPv6 network file |
打開了一個IPV6的網絡文件 |
REG |
regular file |
普通文件 |
FIFO |
FIFO special file |
先進先出的隊列文件 |
unix |
UNIX domain socket |
unix下的域套接字,也稱inter-process communication socket,也就是常說的IPC scoket(進程間的通信scoket),在開發中經常會被使用的一種通訊方式。 |
MPB |
multiplexed block file |
多路復用的塊文件 |
MPC |
multiplexed character file |
多路復用的字符文件 |
inet |
an Internet domain socket |
Intent 域套接字 |
l 第6列展示的是使用character special、block special表示的設備號
l 第7列展示的是文件的大小(前提是文件有效)
l 第8列展示的是操作系統本地文件的node number或者協議類型(在網絡通訊的情況下會展示通訊協議類型,比如如下nginx的LISTEN監聽進程就是一個TCP協議)
l 第9列展示的是文件的絕對路徑或者網絡通訊鏈接的地址、端口、狀態或者掛載點等。
lsof 還可以支持其他的參數使用,常見的使用如下:
l lsof –c 查看某個進程名稱當前打開了哪些文件,例如執行lsof –c nginx命令可以查看nginx進程當前打開了哪些文件
l lsof –p 查看某個進程id 當前打開了哪些文件,例如執行lsof –p 1 命令可以查看進程id為1的進程當前打開了哪些文件
l lsof –i 查看IPv4、IPv6下打開的文件,此時看到的大部分都是網絡的鏈接通訊,會包括服務端的LISTEN監聽或者客戶端和服務端的網絡通訊。
在lsof –i后加上 :(冒號) 端口號時,可以定位到某個端口下的IPv4、IPv6模式打開的文件和該端口下的網絡鏈接通訊,例如執行lsof –i:80命令可以查看一下80端口下的網絡鏈接通訊情況
從這個展示的通訊情況可以看到,80端口下起了兩個LISTEN監聽進程,分別是在root用戶下和nobody用戶下,並且可以看到ip為192.168.1.100的電腦和80端口進行了TCP通訊鏈接,TCP通訊鏈接的狀態為
ESTABLISHED,並且鏈接時占用了服務器上的53151和53152 這兩個端口。
TCP通訊鏈接是在做性能測試時經常需要關注的,尤其是在高並發的情況下如何優化TCP鏈接數和TCP鏈接的快速釋放,是性能調優的一個關注點。鏈接的常用狀態如下
狀態 |
解釋 |
LISTEN |
監聽狀態,這個一般應用程序啟動時,會啟動監聽,比如nginx程序啟動后,就會產生監聽進程,一般的時候,監聽進程的端口都是可以自己進行設置,以防止端口沖突 |
ESTABLISHED |
鏈接已經正常建立,表示客戶端和服務端正在通訊中。 |
CLOSE_WAIT |
客戶端主動關閉連接或者網絡異常導致連接中斷,此時這次鏈接下服務端的狀態會變成CLOSE_WAIT,需要服務端來主動進行關閉該鏈接。 |
TIME_WAIT |
服務端主動斷開鏈接,收到客戶端確認后鏈接狀態變為TIME_WAIT,但是服務端並不會馬上徹底關閉該鏈接,只是修改了狀態。TCP協議規定TIME_WAIT狀態會一直持續2MSL的時間才會徹底關閉,以防止之前鏈接中的網絡數據包因為網絡延遲等原因延遲出現。處於TIME_WAIT狀態的連接占用的資源不會被內核釋放,所以性能測試中如果服務端出現了大量的TIME_WAIT狀態的鏈接就需要分析原因了,一般不建議服務端主動去斷開鏈接。 |
SYN_SENT |
表示請求正在鏈接中,當客戶端要訪問服務器上的服務時,一般都需要發送一個同步信號給服務端的端口,在此時鏈接的狀態就為SYN_SENT,一般SYN_SENT狀態的時間都是非常短,除非是在非常高的並發調用下,不然一般SYN_SENT狀態的鏈接都非常少。 |
SYN_RECV |
表示服務端接收到了客戶端發出的SYN請求並且服務器在給客戶端回復SYN+ACK后此時服務端所處的中間狀態。 |
LAST_ACK |
表示TCP連接關閉過程中的一種中間狀態,關閉一個TCP連接需要發送方和接收方分別都進行關閉,雙方都是通過發送FIN(關閉連接標志)來表示單方向數據的關閉,當通信雙方發送了最后一個FIN的時候,發送方此時處於LAST_ACK狀態。 |
CLOSING |
表示TCP連接關閉過程中的一種中間狀態,一般存在的時間很短不是經常可以看到,在發送方和接收方都主動發送FIN並且在收到對方對自己發送的FIN之前收到了對方發送的FIN的時候,兩邊就都進入了CLOSING狀態。 |
FIN_WAIT1 |
同樣是表示TCP連接關閉過程中的一種中間狀態,存在的時間很短一般幾乎看不到,發送方或者調用方主動調用close函數關閉連接后會立刻進入FIN_WAIT1狀態,此時只要收到對端的ACK確認后馬上會進入FIN_WAIT2狀態。 |
FIN_WAIT2 |
同樣是表示TCP連接關閉過程中的一種中間狀態,主動關閉連接的一方在等待對端FIN到來的過程中通常會一直保持這個狀態。一般網絡中斷或者對端服務很忙還沒及時發送FIN或者對端程序有bug忘記關閉連接等都會導致主動關閉連接的一方長時間處於FIN_WAIT2狀態。如果主動關閉連接的一方發現大量FIN_WAIT2狀態時, 應該需要去檢查是不是網絡不穩定或者對端的程序存在連接泄漏的情況。 |
在TCP協議層中有一個FLAGS字段,這個字段一般包含SYN(建立連接標志)、 FIN(關閉連接標志)、 ACK(響應確認標志)、 PSH(DATA數據傳輸標志)、 RST(連接重置標志)、 URG(緊急標志)這幾種標志,每種標志代表一種連接信號。
不管是什么狀態下的TCP鏈接,都會占用服務器的大量資源,而且每個鏈接都會占用一個端口,Linux服務器的TCP和UDP的端口總數是有限制的(0-65535),超過這個范圍就沒有端口可以用了,程序會無法啟動,鏈接也會無法進行。所以如果服務端出現了大量的CLOSE_WAIT和TIME_WAIT的鏈接時,就需要去及時去查找原因和進行優化。CLOSE_WAIT狀態一般大部分的時候,都是自己寫的代碼或者程序出現了明顯的問題造成。
針對如果出現了大量的TIME_WAIT狀態的鏈接,可以從服務器端進行一些優化以讓服務器快速的釋放TIME_WAIT狀態的鏈接占用的資源。優化的方式如下
使用vim /etc/sysctl.conf來編輯sysctl.conf文件以優化Linux操作系統的文件內核參數設置,加入如下配置:
net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time=600 net.ipv4.tcp_max_tw_buckets = 5000 fs.file-max = 900000 net.ipv4.tcp_max_syn_backlog = 2000 net.core.somaxconn = 2048 net.ipv4.tcp_synack_retries = 1 net.ipv4.ip_local_port_range =1000 65535 net.core.rmem_max = 2187154 net.core.wmem_max = 2187154 net.core.rmem_default = 250000 net.core.wmem_default = 250000
然后執行sysctl –p命令可以內核讓參數立即生效,這種調優一般在nginx、apache 這種web服務器上會經常用到。
- net.ipv4.tcp_syncookies = 1 表示開啟syn cookies,當出現syn等待隊列溢出時啟用cookies來處理,默認情況下是關閉狀態。客戶端向linux服務器建立TCP通訊鏈接時會首先發送SYN包,發送完后客戶端會等待服務端回復SYN+ACK,服務器在給客戶端回復SYN+ACK后,服務器端會將此時處於SYN_RECV狀態的連接保存到半鏈接隊列中以等待客戶端繼續發送ACK請求給服務器端直到最終鏈接完全建立,在出現大量的並發請求時這個半鏈接隊列中可能會緩存了大量的SYN_RECV狀態的鏈接從而導致隊列溢出,隊列的長度可以通過內核參數net.ipv4.tcp_max_syn_backlog進行設置,在開啟cookies后服務端就不需要將SYN_RECV狀態的半狀態鏈接保存到隊列中,而是在回復SYN+ACK時將鏈接信息保存到ISN中返回給客戶端,當客戶端進行ACK請求時通過ISN來獲取鏈接信息以完成最終的TCP通訊鏈接。
- net.ipv4.tcp_tw_reuse = 1 表示開啟鏈接重用,即允許操作系統將TIME-WAIT socket的鏈接重新用於新的tcp鏈接請求,默認為關閉狀態。
- net.ipv4.tcp_tw_recycle = 1 表示開啟操作系統中TIME-WAIT socket鏈接的快速回收,默認為關閉狀態。
- net.ipv4.tcp_fin_timeout = 30 設置服務器主動關閉鏈接時,scoket鏈接保持等待狀態的最大時間。
- net.ipv4.tcp_keepalive_time = 600 表示請求在開啟keepalive(現在一般客戶端的http請求都是開啟了keepalive選項)時TCP發送keepalive消息的時間間隔,默認是7200秒,在設置短一些后可以更快的去清理掉無效的請求。
- net.ipv4.tcp_max_tw_buckets = 5000 表示鏈接為TIME_WAIT狀態時linux操作系統允許其接收的套接字數量的最大值,過多的TIME_WAIT套接字會使Web服務器變慢
- fs.file-max = 900000 表示linux操作系統可以同時打開的最大句柄數,在web服務器中,這個參數有時候會直接限制了web服務器可以支持的最大鏈接數,需要注意的是這個參數是對整個操作系統生效的。而ulimit –n 可以用來查看進程能夠打開的最大句柄數,在句柄數不夠時一般會出現類似” Too many open files”的報錯。在Centos7中可以使用cat /proc/sys/fs/file-max 命令來查看操作系統可以能夠打開的最大句柄數。
- 使用vi /etc/security/limits.conf 編輯limits.conf配置文件,可以修改進程能夠打開的最大句柄數,在limits.conf增加如下配置即可
soft nofile 65535 hard nofile 65535
- net.ipv4.tcp_max_syn_backlog 表示服務器能接受SYN同步包的最大客戶端連接數,也就是上面說的半連接的最大數量,默認值為128
- net.core.somaxconn = 2048 表示服務器能處理的最大客戶端連接數,這里的連接指的是能同時完成連接建立的最大數量,默認值為128
- net.ipv4.tcp_synack_retries = 1 表示服務器在發送SYN+ACK回復后,在未繼續收到客戶端的ACK請求時服務器端重新嘗試發送SYN+ACK回復的重試次數
- net.ipv4.ip_local_port_range =2048 65535 修改可以用於和客戶端建立連接的端口范圍,默認為32768到61000,修改后,可以避免建立連接時端口不夠用的情況。
- net.core.rmem_max = 2187154 表示linux操作系統內核scoket接收緩沖區的最大大小,單位為字節
- net.core.wmem_max = 2187154表示linux操作系統內核scoket發送緩沖區的最大大小,單位為字節
- net.core.rmem_default = 250000 表示linux操作系統內核scoket接收緩沖區的默認大小,單位為字節
- net.core.wmem_default = 250000表示linux操作系統內核scoket發送緩沖區的默認大小,單位為字節
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
l lsof +d 列出指定目錄下被使用的文件,例如執行lsof +d /usr/lib/locale/ 命令查看/usr/lib/locale/ 目錄下有哪些文件被打開使用了
l lsof +D 和上面+d 參數的作用類似,也是列出指定目錄下被使用的文件,不同的是+D會以遞歸的形式列出,也就是會列出指定目錄下所有子目錄下被使用的文件,而-d 參數只會列出當前指定目錄下被使用的文件,
而不會繼續去列出子目錄下被使用的文件,例如執行lsof +D /usr/lib/ 命令查看/usr/lib/ 目錄以及子目錄下有哪些文件被打開使用了
l lsof 后面可以直接指定一個全路徑的文件以列出該文件正在被哪些進程所使用,例如執行lsof /usr/lib/modules/3.10.0-862.el7.x86_64/modules.symbols.bin 命令可以查看到modules.symbols.bin文件目前正在被那個
進程使用
l lsof –i:@ip 可以列出某個指定ip上的所有網絡連接通訊,例如執行lsof -i@192.168.1.221 命令可以查看到192.168.1.221這個ip上的所有的網絡連接通訊
l lsof –i 網絡協議 可以列出某個指定協議下的網絡連接信息
lsof –i tcp 命令可以列出tcp下所有的網絡連接信息
- lsof -i tcp:80 命令可以列出tcp下80端口所有的網絡連接信息
- lsof –i udp 命令可以列出udp下所有的網絡連接信息
- lsof -i udp:323 命令可以列出udp下323端口所有的網絡連接信息
1.1.4 如何通過free看懂內存的真實使用
free命令是linux操作系統中對內存進行查看和監控的一個常用命令,我們可以直接執行free命令來看下可以獲取到操作系統內存使用的哪些數據
默認直接執行free 獲取到的內存數據的單位都是k,Mem這一行展示的是物理內存的使用情況,Swap這一行展示的是內存交換區(通常也叫虛擬內存)的整體使用情況。
l total列展示的為系統總的可用物理內存和交換區的大小,單位為k
l used列展示的為已經被使用的物理內存和交換區的大小,單位為k
l free列展示的為還有多少物理內存和交換區沒有被使用,單位為k
l shared 列展示的為共享區占用的物理內存大小,單位為k
l buff/cache 列展示的為被緩沖區和page高速緩存合計使用的物理內存大小,單位為k
- buff在操作系統中指的是緩沖區,是負責磁盤塊設備的讀寫緩沖,會直接占用物理內存。
- cache 指的是操作系統中的 page cache(也就是通常所說的高速緩存),高速緩存是linux內核實現的磁盤緩存,可以減少內核對磁盤的I/O讀寫操作,會將磁盤中的數據緩存到物理內存中,這樣對磁盤的訪問就會變為對物理內存的訪問,從而大大提高了讀寫速度。cache 有一點類似應用程序中使用redis來做緩存一樣,把一些經常需要訪問的數據存儲到內存中來提高訪問的速度。
l available 列展示的為還可以被使用的物理內存的大小,單位為k。通常情況下,available 的值等於free+ buff/cache ,linux內核為了提高磁盤讀寫的速度會使用一部分物理內存去緩存經常被使用的磁盤數據,所以buffer 和 cache對於Linux操作系統的內核來說都屬於已經被使用的內存,而free列展示的是真實未被任何地方使用的物理內存,但是如果物理內存已經不夠用並且應用程序恰巧又需要使用內存時內核就會從 buffer 和 cache 中回收內存來滿足應用程序的使用,也就是說buffer 和 cache占用的內存是可以被內核釋放的。
1.1.5 、 網絡流量如何監控
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。
在linux中,可以使用iftop命令來對服務器網卡的網絡流量進行監控,iftop並不是linux操作系統中本身就有的工具,需要單獨進行安裝,可以從http://www.ex-parrot.com/~pdw/iftop/ 網站中下載iftop工具。
下載完成后,首先執行./configure 命令進行安裝前的自動安裝配置檢查
[root@localhost iftop-1.0pre4]# ./configure
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
........
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config/Makefile
config.status: creating config.h
config.status: executing depfiles commands
configure: WARNING:
******************************************************************************
This is a pre-release version. Pre-releases are subject to limited
announcements, and therefore limited circulation, as a means of testing
the more widely circulated final releases.
Please do not be surprised if this release is broken, and if it is broken, do
not assume that someone else has spotted it. Instead, please drop a note on
the mailing list, or a brief email to me on pdw@ex-parrot.com
Thank you for taking the time to be the testing phase of this development
process.
Paul Warren
******************************************************************************
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
配置安裝檢查通過后,執行make && make install 命令對源碼先進行編譯,然后進行安裝
[root@localhost iftop-1.0pre4]# make && make install
make all-recursive
make[1]: Entering directory `/home/iftop/iftop-1.0pre4'
Making all in config
make[2]: Entering directory `/home/iftop/iftop-1.0pre4/config'
make[2]: Nothing to be done for `all'.
make[2]: Leaving directory `/home/iftop/iftop-1.0pre4/config'
make[2]: Entering directory `/home/iftop/iftop-1.0pre4'
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT addr_hash.o -MD -MP -MF .deps/addr_hash.Tpo -c -o addr_hash.o addr_hash.c
mv -f .deps/addr_hash.Tpo .deps/addr_hash.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT edline.o -MD -MP -MF .deps/edline.Tpo -c -o edline.o edline.c
mv -f .deps/edline.Tpo .deps/edline.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT hash.o -MD -MP -MF .deps/hash.Tpo -c -o hash.o hash.c
mv -f .deps/hash.Tpo .deps/hash.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT iftop.o -MD -MP -MF .deps/iftop.Tpo -c -o iftop.o iftop.c
mv -f .deps/iftop.Tpo .deps/iftop.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT ns_hash.o -MD -MP -MF .deps/ns_hash.Tpo -c -o ns_hash.o ns_hash.c
mv -f .deps/ns_hash.Tpo .deps/ns_hash.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT options.o -MD -MP -MF .deps/options.Tpo -c -o options.o options.c
mv -f .deps/options.Tpo .deps/options.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT resolver.o -MD -MP -MF .deps/resolver.Tpo -c -o resolver.o resolver.c
mv -f .deps/resolver.Tpo .deps/resolver.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT screenfilter.o -MD -MP -MF .deps/screenfilter.Tpo -c -o screenfilter.o screenfilter.c
mv -f .deps/screenfilter.Tpo .deps/screenfilter.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT serv_hash.o -MD -MP -MF .deps/serv_hash.Tpo -c -o serv_hash.o serv_hash.c
mv -f .deps/serv_hash.Tpo .deps/serv_hash.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT sorted_list.o -MD -MP -MF .deps/sorted_list.Tpo -c -o sorted_list.o sorted_list.c
mv -f .deps/sorted_list.Tpo .deps/sorted_list.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT threadprof.o -MD -MP -MF .deps/threadprof.Tpo -c -o threadprof.o threadprof.c
mv -f .deps/threadprof.Tpo .deps/threadprof.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT ui_common.o -MD -MP -MF .deps/ui_common.Tpo -c -o ui_common.o ui_common.c
mv -f .deps/ui_common.Tpo .deps/ui_common.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT ui.o -MD -MP -MF .deps/ui.Tpo -c -o ui.o ui.c
mv -f .deps/ui.Tpo .deps/ui.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT tui.o -MD -MP -MF .deps/tui.Tpo -c -o tui.o tui.c
mv -f .deps/tui.Tpo .deps/tui.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT util.o -MD -MP -MF .deps/util.Tpo -c -o util.o util.c
mv -f .deps/util.Tpo .deps/util.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT addrs_ioctl.o -MD -MP -MF .deps/addrs_ioctl.Tpo -c -o addrs_ioctl.o addrs_ioctl.c
mv -f .deps/addrs_ioctl.Tpo .deps/addrs_ioctl.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT addrs_dlpi.o -MD -MP -MF .deps/addrs_dlpi.Tpo -c -o addrs_dlpi.o addrs_dlpi.c
mv -f .deps/addrs_dlpi.Tpo .deps/addrs_dlpi.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT dlcommon.o -MD -MP -MF .deps/dlcommon.Tpo -c -o dlcommon.o dlcommon.c
mv -f .deps/dlcommon.Tpo .deps/dlcommon.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT stringmap.o -MD -MP -MF .deps/stringmap.Tpo -c -o stringmap.o stringmap.c
mv -f .deps/stringmap.Tpo .deps/stringmap.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT cfgfile.o -MD -MP -MF .deps/cfgfile.Tpo -c -o cfgfile.o cfgfile.c
mv -f .deps/cfgfile.Tpo .deps/cfgfile.Po
gcc -DHAVE_CONFIG_H -I. -g -O2 -MT vector.o -MD -MP -MF .deps/vector.Tpo -c -o vector.o vector.c
mv -f .deps/vector.Tpo .deps/vector.Po
gcc -g -O2 -o iftop addr_hash.o edline.o hash.o iftop.o ns_hash.o options.o resolver.o screenfilter.o serv_hash.o sorted_list.o threadprof.o ui_common.o ui.o tui.o util.o addrs_ioctl.o addrs_dlpi.o dlcommon.o stringmap.o cfgfile.o vector.o -lpcap -lm -lcurses -lpthread
make[2]: Leaving directory `/home/iftop/iftop-1.0pre4'
make[1]: Leaving directory `/home/iftop/iftop-1.0pre4'
Making install in config
make[1]: Entering directory `/home/iftop/iftop-1.0pre4/config'
make[2]: Entering directory `/home/iftop/iftop-1.0pre4/config'
make[2]: Nothing to be done for `install-exec-am'.
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/home/iftop/iftop-1.0pre4/config'
make[1]: Leaving directory `/home/iftop/iftop-1.0pre4/config'
make[1]: Entering directory `/home/iftop/iftop-1.0pre4'
make[2]: Entering directory `/home/iftop/iftop-1.0pre4'
/usr/bin/mkdir -p '/usr/local/sbin'
/usr/bin/install -c iftop '/usr/local/sbin'
/usr/bin/mkdir -p '/usr/local/share/man/man8'
/usr/bin/install -c -m 644 iftop.8 '/usr/local/share/man/man8'
make[2]: Leaving directory `/home/iftop/iftop-1.0pre4'
make[1]: Leaving directory `/home/iftop/iftop-1.0pre4'
命令執行完成后,可以看到iftop已經被安裝到/usr/local/sbin目錄下了
完成iftop的安裝后,就可以直接執行iftop命令了,命令執行后可以看到如下圖的網絡流量使用信息
l 代表了網絡流量的流轉方向
l TX:表示發送的總流量
l RX:表示接收的總流量
l TOTAL:表示總流量
l peak:表示每秒流量的峰值
l rates:分別表示過去 2s 10s 40s 的平均流量
iftop 命令還可以支持添加其它參數的使用
iftop –i 指定網卡名 可以用來監控指定網卡的網絡流量信息,例如執行iftop -i ens33命令可以監控ens33這塊網卡的網絡流量使用
iftop –P 可以在網絡流量信息中展示host信息和對應的端口信息,如下圖所示
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。
1.1.6、 nmon對Linux服務器的整體性能監控
nmon 是一個監控aix和linux服務器性能的免費工具,nmon可以監控的數據主要包括:CPU 使用信息、內存使用信息,內核統計信息、運行隊列信息、磁盤 I/O 速度、傳輸和讀/寫比率、網絡 I/O 速度、傳輸和讀/寫比
率、消耗資源最多的進程,虛擬內存使用信息等,配合nmon_analyser一起可以nmon的監控數據轉換為excel形式的報表,nmon也不是操作系統自帶的監控工具,需要單獨進行安裝,可以從、
https://sourceforge.net/projects/nmon/網站中下載nmon進行安裝使用。
安裝完成后,執行nmon 命令后,可以進入nmon的監控選項視圖
- 鍵盤按下c后,可以實時監控到服務器CPU中每一個CPU核的使用信息
- 鍵盤按下l后,可以實時監控CPU的整體使用信息,此時展示的不再是單個CPU核的使用信息,而是所有CPU核整體的平均使用信息,如下圖所示
- 鍵盤按下m后,可以實時監控到服務器的物理內存和虛擬內存的使用信息
- 鍵盤按下k后,可以實時監控到服務器的內核信息
內核監控中可以看到操作系統內核中的運行隊列(RunQueue)大小、每秒CPU上下文(ContextSwitch)切換的次數、每秒CPU的中斷(Interrupts)次數,每秒調用Forks的次數(Linux操作系統創建新的進程一般都是調用fork函數進行創建,從中可以看到每秒創建了多少新的進程)以及CPU的使用信息等。
- 鍵盤按下d后,可以實時監控到服務器的磁盤I/O的讀寫信息
- 鍵盤按下j后,可以實時監控到服務器的文件系統的相關信息
- 鍵盤按下n后,可以實時監控到服務器網卡流量的相關信息
- 鍵盤按下t后,可以實時監控top process的相關資源使用信息
1.1.7、 如何通過top發現問題
在性能測試時,linux操作系統中還可以通過top命令來發現和定位服務器性能消耗問題,執行top命令后獲取到的數據如下圖所示。
從圖中可以看到:
- 第一行展示的為系統運行信息:系統當前時間為02:11:13、系統運行了41分鍾、當前登錄的用戶有2個、系統的平均負載壓力情況為0.00(1分鍾的平均負載壓力) 0.01(5分鍾的平均負載壓力) 0.05(15分鍾的平均負載壓力),load average數據是每隔5秒鍾檢查一次活躍的進程數,然后按特定算法計算出的數值,一般當這個數值除以CPU的核數得到的值大於3-5時就表明系統的負載壓力已經超高了。
- 第二行展示的為任務信息:總共108個進程、1個進程正在占用CPU進行運行、107個進程正在休眠中、0個進程停止、0個進程假死。
- 第三行展示的為CPU的運行信息:0.0 us表示 用戶模式下CPU占用比為0.0%,0.2 sy 表示系統模式下CPU占用比為0.2%,0.0 ni表示改變過優先級的進程的CPU占用比為0.0%,99.8 id 表示空閑狀態的CPU占比為99.8%,0.0 wa 表示因為I/O等待造成的CPU占比為0.0%,0.0 hi表示硬中斷的CPU占比,0.0 si 表示軟中斷的CPU的占比,0.0 st表示CPU等待虛擬機調度的時間占比,這個指標一般在虛擬機中才會有,物理機中,該值一般維持為0。
- 第四行展示的為內存的使用信息:1865308 total 表示物理內存的總量, 1457604 free表示物理內存的空閑大小, 198808 used表示已使用的物理內存的大小, 208896 buff/cache表示用作緩存的物理內存的大小
- 第五行展示的為虛擬內存(swap)的使用信息:2097148 total 表示虛擬內存空間大小, 2097148 free 表示虛擬內存空間的空閑大小, 0 used表示虛擬內存空間的使用大小. 1479036 avail Mem 表示還可以被使用的有效內存大小。
- 第七行展示的為每個進程的資源消耗信息,詳情如下表所示。
列名 |
描述 |
PID |
進程id編號 |
USER |
進程的持有用戶 |
PR |
進程運行的優先級,值越小優先級就越高,會越早獲得CPU的執行權。
|
NI |
進程的nice值,表示進程可被執行的優先級的修正數值 |
VIRT |
進程使用的虛擬內存總大小,單位為KB |
RES |
進程使用的並且未被虛擬內存換出的物理內存大小,一般也稱為常駐內存,單位為KB |
SHR |
進程使用的共享內存大小,單位為KB |
S |
進程當前的運行狀態。 D:不可中斷的睡眠狀態 R:運行中 S:休眠中 T:跟蹤/停止 Z:假死中 |
%CPU |
進程運行時CPU的占比 |
%MEM |
進程使用的內存占比 |
TIME+ |
進程占用的CPU總時長 |
COMMAND |
正在運行的命令 |
top命令支持的其它常用參數如下:
- top –p:查看指定進程id的top信息,例如執行top -p 2081可以查看進程編號為2081的top信息,如下圖所示。
- top –H –p:查看指定進程id的所有線程的top信息,例如執行top -H -p 2081可以查看進程編號為2081的所有線程的top信息,如下圖所示,此時圖中的PID展示的為線程的id編號。
通過top --help還可以查看到更多的關於top命令的參數使用信息。
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
1.1.8、 如何通過pidstat發現性能問題
pidstat是針對Linux操作系統中某個進程進行資源監控的一個常用命令。使用該命令可以列出每個進程id占用的資源情況,如下圖所示。
另外還可以通過在pidstat 命令后面增加數字參數來輪詢獲取資源使用的數據,例如執行pidstat 1 3 可以輪詢每隔1s自動獲取3個活動的進程的CPU使用情況,如下圖所示。
執行pidstat后獲得的性能監控指標詳細說明如下表所示:
指標 |
含義 |
UID |
用戶id |
PID |
進程id |
%usr |
進程對用戶模式cpu使用時間的百分比 |
%system |
進程對系統模式cpu使用時間的百分比 |
%guest |
進程在虛擬機(運行虛擬處理器)中占用的cpu百分比 |
%CPU |
指定進程使用cpu的時間的百分比 |
CPU |
執行指定進程的cpu編號 |
Command |
當前進程運行的命令 |
pidstat還可以支持其他的參數使用,我們可以通過執行pidstat --help 命令查看到它支持的其他參數,如下圖所示。
- pidstat –d:展示每個進程的I/O使用情況,如下圖所示:
指標 |
含義 |
kB_rd/s |
進程每秒從磁盤讀取的數據大小,單位為KB |
kB_wr/s |
進程每秒寫入磁盤的數據大小,單位為KB |
kB_ccwr/s |
進程寫入磁盤被取消的數據大小,單位為KB |
- pidstat –p:如果只需要看指定進程id的資源使用情況,可以通過-p參數來進行指定,例如執行pidstat -p 1533 可以看到進程編號為1533的進程占用的CPU資源情況,如下圖所示。
執行pidstat -d -p 1533可以看到進程編號為1533的進程的I/O使用情況,如下圖所示。
- pidstat –r:展示每個進程的內存使用情況,如下圖所示:
指標 |
含義 |
minflt/s |
進程讀取內存數據時每秒出現的次要錯誤的數量,這些錯誤指的是不需要從磁盤載入內存的數據,一般是虛擬內存地址映射成物理內存地址所產生的page fault次數。 |
majflt/s |
進程讀取內存數據時每秒出現的主要錯誤的數量,這些錯誤指的是需要從磁盤載入內存的數據。當虛擬內存地址映射成物理內存地址時,相應的page數據在swap中,這樣的page fault(頁面數據錯誤)為major page fault(主要頁面數據錯誤),一般在物理內存使用緊張時才產生。 |
VSZ |
進程占用的虛擬內存的大小,單位為KB |
RSS |
進程占用的物理內存的大小,單位為KB |
%MEM |
進程占用的內存百分比 |
- pidstat –u:和執行pidstat 命令獲取的數據是一致的。
- pidstat –w:展示每個進程的CPU上下文切換次數,如下圖所示。
指標 |
含義 |
cswch/s |
每秒主動進行cpu上下文切換的數量,一般由於需要的資源不可用而發生阻塞時,會自願主動進行上下文切換。 |
nvcswch/s |
每秒被動進行cpu上下文切換的數量,比如當進程在其cpu時間片內執行,然后由於cpu時間片調度被迫放棄該cpu處理器時,會發生被動非自願的上下文切換。 |
- pidstat –l: 顯示進程正在執行的命令以及該命令對應的所有參數,如下圖所示。
- pidstat –t:展示進程以及進程對應的線程的資源使用情況,如下圖所示。
圖中的TGID表示的就是進程id,而TID表示的是對應的進程id下的線程id。
例如還可以執行pidstat -r -t -p 1533 來查看進程id為1533的進程以及該進程對應的線程的內存使用情況,如下圖所示。
- pidstat –s:展示每個進程的堆棧使用情況,如下圖所示。
指標 |
含義 |
StkSize |
進程保留在內存中的堆棧占用的內存大小,單位為KB,這些堆棧數據並一定全部會被進程使用。 |
StkRef |
進程實際引用的用作堆棧的內存大小(即實際使用的堆棧空間大小),單位為KB。 |
- pidstat –U:展示進程的資源使用數據時同時展示進程id對應的用戶名稱,如下圖所示,USER列可以看到用戶的名稱。
1.2、 Windows服務器的性能指標監控和分析
1.2.1、 Windows性能監視器
Windows服務器在安裝完Windows操作系統后,操作系統中默認就自帶了性能監控工具,這個自帶的性能監控工具通過訪問操作系統的控制面板->所有控制面板項->管理工具->性能監視器就能打開自帶的這個性能監控工
具,也可以通過在命令行中運行Perfmon.msc命令來打開自帶的性能監控工具,打開后的界面如下圖所示。
在Windows2003服務器操作系統中,這個性能監控工具是直接叫性能,如下圖所示
在Windows2003中,打開性能監控工具的界面如下圖所示,界面展示略有不同,但是包含的功能基本一致。
針對Processor、Process、Memory、TCP/UDP/IP/ICMP、PhysicalDisk等監控對象,Windows自帶的性能監視器提供了數百個性能計數器可以對這些對象進行監控,計數器可以提供應用程序、Windows服務、操作系統等的相關的性能信息來輔助分析程序性能瓶頸和對系統及應用程序性能進行診斷和調優。
在進入性能監視器界面后,可以通過點擊按鈕來添加對應的計數器,如下圖所示。
常見的計數器如下
l Processor:指的就是Windows服務器的CPU,在添加時會有實例的選擇,每一個實例代表了CPU的每一個核,比如4核的CPU的就會有4個實例,可以根據需要選擇對應的實例,在選擇了Processor后,可以看到該實例下所有和Processor相關的計數器,如下圖
Processor相關的計數器指標說明如下
計數器 |
說明 |
%Processor Time |
CPU執行非閑置進程和線程時間的百分比(可以通俗的理解為CPU處於繁忙使用狀態的時間占比),該計數器一般可以用來作為CPU的整體利用率指標 |
%User Time |
CPU處於用戶模式下的使用時間占比,該計數器和Linux下的%usr指標含義類似 |
%Privileged Time |
CPU在特權模式下處理線程所花的時間占比,該計數器一般可以作為系統服務、操作系統自身模式下耗費的CPU時間占比,這個指標一般不會太高,如果太高就需要去定位原因,一般的時候%User Time越高,說明CPU被利用的越好。 |
Interrupts/sec |
CPU每秒的中斷次數, 該計數器和Linux下的in指標的含義類似 |
%Interrupt Time |
CPU中斷時間占比,該計數器和Linux下的%irq指標的含義類似 |
%Idle Time |
CPU空閑時間占比,該計數器和Linux下的%idle指標的含義類似 |
%DPC Time |
CPU處理網絡傳輸等待的時間占比 |
l Memory:指的就是Windows服務器的物理內存,在選擇了Memory后,可以看到該實例下所有和Memory相關的計數器,如下圖
Memory相關的計數器指標說明如下
計數器 |
說明 |
Available Bytes |
服務器剩余的可用物理內存的大小(單位為字節),如果該值很小說明服務器總的內存可能不夠或者部分應用一直都沒有及時釋放內存, 服務器的可用物理內存是通過將程序釋放的內存、空閑內存、備用內存相加在一起計算出來的。 |
Committed Bytes |
已被提交的虛擬內存字節數,內存分配時會先在虛擬地址空間上保留一段空間保留一段時間,此時系統還沒有分配真正的物理內存只是分配了一段內存地址,在這一步操作成功后再提交分配的這段內存地址,操作系統接收到提交的內存地址后才會分配真正的物理內存。 |
Page Faults/sec |
每秒缺頁中斷或者頁面錯誤的數量,一般內存中不存在需要訪問的數據導致需要從硬盤讀取可能會導致此指標較高。 |
Reads/sec |
每秒為了解決硬錯誤(一般指引用的頁面在內存中不存在)而從硬盤上讀取頁面的次數 |
Writes/sec |
每秒為了釋放物理內存空間而需要將頁面寫入磁盤的次數 |
Input/sec |
每秒為了解決硬錯誤而從硬盤讀取的頁面數量,一般是指內存引用時頁面不在內存,為解決這種情況而從磁盤讀取的頁面數量。 |
Output/sec |
每秒內存中的頁面發生了修改從而需要寫入磁盤的頁面數量 |
Pages/sec |
每秒為了解決硬錯誤(一般指引用的頁面在內存中不存在)而從硬盤上讀取或寫入硬盤的頁面數量 |
Cathe Bytes |
Windows文件系統的緩存,這塊也是占用服務器的物理內存,但是在物理內存不夠時是可以釋放的,Windows在釋放內存時一般會使用頁交換的方式進行,頁交換會將固定大小的代碼和數據塊從 物理內存移動到磁盤。 |
Pool Nonpaged Allocs |
在非分頁池中分配空間的調用數,這個計數器是以調用分配空間的次數來衡量的,而不會管每次調用分配的空間量是多少。 一般內核或者設備驅動使用非分頁池來保存可能訪問的數據,一旦加載到該池就始終駐留在物理內存中,並且在訪問的時候又不能出現錯誤,未分頁池不執行換入換出操作,如果一旦發生內存泄漏,將會非常嚴重。與非分頁池對應的就是分頁池(Paged Pool),指的是可以存到操作系統的分頁文件中,允許其占用的物理內存被重新設置,類似用戶模式的虛擬內存。 |
Pool Nonpaged Bytes |
非分頁池的大小(單位:字節)。內存池非分頁字節的計算方式不同於進程池中非分頁字節,因此它可能不等於進程池非分頁字節總數。 |
Pool Paged Allocs |
在分頁池中分配空間的調用數。它也是以調用分配空間的次數來衡量的,而不管每次調用分配的空間量是多少。 |
Pool Paged Bytes |
分頁池的大小(單位:字節)。內存池分頁字節的計算方式與進程池分頁字節的計算方式不同,因此它可能不等於進程池分頁字節總數。 |
Transition Faults/sec |
通過恢復共享頁中被其它進程正在使用的頁、已修改頁列表或待機列表中的頁、或在頁故障時寫入磁盤的頁來解決頁故障的速率。在沒有其他磁盤活動的情況下恢復了這些頁。轉換錯誤按錯誤數計算,因為每個操作中只有一個頁面出錯,所以它也等於出錯的頁面數。 |
Write Copies/sec |
通過從物理內存中的其他位置復制頁來滿足的寫入嘗試導致頁錯誤的速率。這是一種效率很高的共享數據的方式,因為頁面只在寫入時被復制,否則頁面被共享。此計數器只顯示副本數而不考慮每次操作中復制的頁數。 |
System Code Total Bytes |
虛擬內存中當前可分頁給操作系統程序的空間大小(單位:字節)。它是操作系統使用的物理內存量的量度並且可以在不使用時寫入磁盤。這個值是通過添加ntoskrnl.exe、hal.dll、引導驅動程序和ntldr/osloader加載的文件系統中的字節來計算的。此計數器不包括必須保留在物理內存中且無法寫入磁盤的操作系統程序。 |
System Driver Total Bytes |
設備驅動程序當前使用的可分頁虛擬內存的大小(單位:字節),包括物理內存(內存/系統驅動程序駐留空間)和寫入磁盤的代碼和數據。它是內存/系統代碼總字節數的組成部分 |
l PhysicalDisk:指的就是Windows服務器的磁盤設備,在選擇了PhysicalDisk后,可以看到該實例下所有和PhysicalDisk相關的計數器,如下圖
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html
PhysicalDisk相關的計數器指標說明如下
計數器 |
說明 |
Disk Bytes/sec |
每秒從磁盤I/O讀取和寫入的字節數 |
Disk Read Bytes/sec |
每秒從磁盤I/O讀取的字節數,這個計數器是以字節大小來描述每秒對磁盤的讀取操作。 |
Disk Write Bytes/sec |
每秒寫入磁盤I/O的字節數,這個計數器是以字節大小來描述每秒對磁盤的寫入操作。 |
Disk Reads/sec |
對磁盤讀取操作的速率,這個計數器是以每秒對磁盤I/O的讀取次數來描述對磁盤的讀取頻率 |
Disk Writes/sec |
對磁盤寫入操作的速率,這個計數器是以每秒對磁盤I/O的寫入次數來描述對磁盤的寫入頻率 |
Disk Transfers/sec |
每秒對磁盤I/O讀取和寫入的次數 |
%Disk Time |
所選磁盤驅動器正忙於處理讀取或寫入請求所用時間占比 |
%Disk Read Time |
所選磁盤驅動器正忙於處理讀取請求的時間占比 |
%Disk Write Time |
所選磁盤驅動器正忙於處理寫入磁盤請求的時間占比 |
Avg. Disk Queue Length |
所選磁盤在性能監視器性能數據采樣間隔期間需要排隊的平均讀寫請求數 |
Avg. Disk Read Queue Length |
所選磁盤在性能監視器性能數據采樣間隔期間需要排隊的平均讀取請求數 |
Avg. Disk Write Queue Length |
所選磁盤在性能監視器性能數據采樣間隔期間需要排隊的平均寫入請求數 |
Split IO/Sec |
對磁盤I/O的讀寫請求拆分為多個請求的速率。分割I/O可能是由於請求的數據太大,無法容納單個I/O,或者物理磁盤在單個磁盤系統上已經被被分割。 |
l IPv4:指的就是Windows服務器的IPv4網絡請求,在選擇了IPv4后,可以看到該實例下所有和IPv4相關的計數器,如下圖
IPv4相關的計數器指標說明如下
計數器 |
說明 |
Datagrams/sec |
服務器每秒發送和接收到的請求報文數 |
Datagrams Received/sec |
服務器每秒接收到的請求報文數 |
Datagrams Received Header Errors/sec |
服務器每秒接收到的請求報文中header 錯誤的數量 |
Datagrams Received Address Errors/sec |
服務器每秒接收到的請求報文中請求地址錯誤的數量 |
Datagrams Forwarded/sec |
服務器每秒轉發的請求報文數 |
Datagrams Received Unknown Protocol/sec |
服務器每秒接收到無法處理的未知網絡協議的請求報文數 |
Datagrams send/sec |
服務器每秒發送的報文數 |
l Process:指的就是Windows服務器的進程監控,在選擇了Process后,可以看到該實例下所有和Process相關的計數器,如下圖
Process相關的計數器指標說明如下
計數器 |
說明 |
Thread Count |
表示當前正在運行的線程數 |
Virtual Bytes |
表示進程占用的全部虛擬地址空間大小(單位為字節),包括進程間的共享地址空間 |
Virtual BytesPeak |
表示進程占用的全部虛擬地址空間的峰值大小,峰值表示從服務器開始運行一直到現在的時間中曾經使用的最大值。 |
Working Set |
表示進程工作集占用內存的大小,包含了每個進程下的各個線程引用過的頁面空間以及可能被其他程序共享的內存空間。 |
WorkingSetPeak |
表示進程工作集占用內存的峰值大小,峰值表示從服務器開始運行一直到現在的時間中曾經使用的最大值。 |
Private Bytes |
表示進程占用的虛擬地址空間大小(單位為字節),並且不包括進程間的共享地址空間,可以認為占用的空間大小是進程私有使用的。 |
Handle Count |
表示進程使用的kernel object handle數量,當程序進入穩定運行狀態的時候, Handle Count數量也應該維持在一個穩定的區間。 如果發現Handle Count在整個程序周期內總體趨勢連續向上,應該考慮程序是否有Handle 泄漏。 |
Pool Paged Bytes |
表示分頁池的使用大小,單位為字節 |
Pool Nonpaged Bytes |
表示非分頁池的使用大小,單位為字節 |
1.2.2、 Windows性能監視器下的性能分析
l 內存泄漏:Windows服務器下借助性能監視器的計數器分析內存泄漏問題的一般步驟如下:
如果剩余的有效物理內存一直在減少並且已提交的虛擬內存一直在增加,那么此時程序代碼可能存在內存泄漏的風險,但是此時還需要觀察Process計數器中的Private Bytes和Working Set是不是也在持續增加,
如果同樣在持續增加那么從服務器端監控看存在內存泄漏的可能性就非常大了,此時就需要去看部署在服務器上的程序是不是存在內存不能回收的情況,可以停止壓測,看下內存使用是否會釋放和回落。另外如果
觀察到HandleCount 的使用一直上漲,那么可能是內核模式進程導致了內存泄露,那么此時就還需要持續觀察內存分頁池中的Paged Bytes和 Pool Paged Bytes是不是也是在一直上漲。
未完待續.......
軟件性能測試、分析與調優實踐之路目錄提綱(計划2020年上架出版)
序... 4
1 性能測試和性能分析的基礎概念... 5
1.1. 性能測試的基礎概念... 5
1.1.1 性能測試的分類... 6
1.1.2 性能測試的場景... 6
1.2. 常見的性能測試指標... 7
1.2.1 響應時間... 7
1.2.2 TPS/QPS. 8
1.2.3 並發用戶... 8
1.2.4 PV/UV.. 8
1.2.5 點擊率... 9
1.2.6 吞吐量... 9
1.2.7 資源開銷... 9
1.3. 性能測試的目標... 10
1.4. 性能測試的基本流程... 11
1.4.1 性能需求分析... 11
1.4.2 制定性能測試計划... 12
1.4.3 編寫性能測試方案... 13
1.4.4 編寫性能測試案例... 15
2 性能分析與調優思想... 15
2.1 性能分析調優模型... 15
2.2 性能分析調優思想... 18
2.2.1 分層分析... 18
2.2.2 科學論證... 19
2.2.3 問題追溯與歸納總結... 19
2.3 性能調優技術... 22
2.3.1 緩存調優... 22
2.3.2 同步轉異步推送... 23
2.3.3 拆分... 23
2.3.4 任務分解與並行計算... 24
2.3.5 代碼優化... 24
2.3.6 索引與分庫分表... 24
3 服務器的性能監控和分析... 24
3.1 Linux服務器的性能指標監控和分析... 25
3.1.1 通過vmstat深挖服務器的性能問題... 25
3.1.2 如何通過mpstat 分析服務器的性能指標... 29
3.1.3 如何通過pidstat發現性能問題... 31
3.1.4 從lsof中能看到什么... 39
3.1.5 如何通過free看懂內存的真實使用... 49
3.1.6 如何通過top發現問題... 50
3.1.7 網絡流量如何監控... 54
3.1.8 nmon對Linux服務器的整體性能監控... 61
3.2 Windows服務器的性能指標監控和分析... 64
3.2.1 Windows性能監視器... 64
3.2.2 Windows性能監視器下的性能分析... 79
4 web中間件的性能分析... 84
4.1 nginx的性能分析和調優... 84
4.1.1 nginx的負載均衡策略的選擇... 84
4.1.2 nginx進程數的配置優化... 87
4.1.3 nginx事件處理模型的優化... 87
4.1.4 nginx客戶端連接數的優化... 90
4.1.5 nginx中文件傳輸的優化... 91
4.1.6 nginx中FastCGI配置的優化... 94
4.1.7 nginx的監控... 97
4.2 apache的性能分析和調優... 99
4.2.1 apache的工作模式選擇和進程數調優... 99
4.2.2 apache的mod選擇和優化... 104
4.2.3 apache的keepAlive優化... 107
4.2.4 apache的ab壓力測試工具... 108
4.2.5 apache的性能監控... 111
5 應用中間件的性能分析... 112
5.1 tomcat的性能分析和調優... 113
5.1.1 tomcat的組件以及工作原理... 113
5.1.2 tomcat容器Connector性能參數優化... 118
5.1.3 tomcat容器的I/O優化... 120
5.2 wildfly的性能分析和調優... 125
5.2.1 wildfly standalone模式介紹... 125
5.2.2 wildfly standalone模式管理控制台性能參數優化... 129
5.2.3 wildfly standalone模式性能監控... 140
6 java應用程序的性能分析和調優... 149
6.1 jvm基礎知識... 149
6.1.1 jvm簡介... 149
6.1.2 類加載器... 151
6.1.3 java虛擬機棧和本地方法棧... 154
6.1.4 方法區與元數據區... 154
6.1.5 堆區... 155
6.1.6 程序計數器... 157
6.1.7 垃圾回收... 157
6.1.8 並行與並發... 162
6.1.9 垃圾回收器... 163
6.2 jvm如何監控... 165
6.2.1 jconsole. 165
6.2.2 jvisualvm.. 173
6.2.3 jmap. 186
6.2.4 jstat 187
6.3 jvm性能分析與診斷... 188
6.3.1 如何讀懂gc日志... 188
6.3.2 jstack. 193
6.3.3 MemoryAnalyzer. 200
6.4 jvm性能調優技巧... 211
6.4.1 如何減少gc. 211
6.4.2 另類java內存泄漏... 213
7 數據庫的性能分析... 214
7.1 mysql數據庫的性能監控... 214
7.1.1 如何查看mysql數據庫的連接數... 214
7.1.2 如何查看mysql數據庫當前運行的事務與鎖... 214
7.1.3 mysql中數據庫表的監控... 218
7.1.4 性能測試時mysql中其它常用監控... 222
7.2 mysql數據庫的性能定位... 225
7.2.1 慢sql 225
7.2.2 執行計划... 226
8 性能測試案例分析... 229
8.1 jmeter對http 服務的性能壓測分析... 229
8.2 LoadRunner對http 服務的性能壓測分析... 243
8.3 jmeter對rpc 服務的性能壓測分析... 262
8.3.1 jmeter 如何通過自定義Sample來壓測RPC服務... 262
8.3.2 jmeter對GRPC服務的性能壓測分析... 273
9 安卓APP的性能分析... 281
9.1 adb. 281
9.2 DDMS. 284
9.3 Android Studio profiler 299
9.4 systrace 306
備注:作者的原創文章,轉載須注明出處。原創文章歸作者所有,歡迎轉載,但是保留版權。對於轉載了博主的原創文章,不標注出處的,作者將依法追究版權,請尊重作者的成果。
本文作者:張永清 文章選自 作者2020年初即將出版的《軟件性能測試、分析與調優實踐之路》一書。文章鏈接:https://www.cnblogs.com/laoqing/p/11629941.html