對(duì)于程序員來(lái)說(shuō),整個(gè)計(jì)算機(jī)系統(tǒng)由四個(gè)重要的模塊組成,分別是:CPU,網(wǎng)絡(luò),磁盤,內(nèi)存。在我們的程序或者系統(tǒng)出現(xiàn)問(wèn)題時(shí),我們應(yīng)該分別有一定先后順序的對(duì)這四塊進(jìn)行排查。而在Linux系統(tǒng)下,有很多高效的工具,可以幫助我們分析定位問(wèn)題。本文對(duì)于Linux下常用的一些工具進(jìn)行一些簡(jiǎn)單的介紹,幫助讀者能對(duì)這些工具有一個(gè)初步的了解。如果有不對(duì)的地方,歡迎隨時(shí)指正交流。
1.CPU
對(duì)于cpu我們主要介紹top,strace,perf,vmstat。
1.1 top
top命令可以實(shí)時(shí)動(dòng)態(tài)地查看系統(tǒng)的整體運(yùn)行情況,是一個(gè)綜合了多方信息監(jiān)測(cè)系統(tǒng)性能和運(yùn)行信息的實(shí)用工具。
Top常用的可選參數(shù)和其對(duì)應(yīng)的含義如下:
(1)-c:顯示完整的命令;
(2)-d:屏幕刷新間隔時(shí)間;
(3)-i<時(shí)間>:設(shè)置間隔時(shí)間;
(4)-u<用戶名>:指定用戶名;
(5)-p<進(jìn)程號(hào)>:指定進(jìn)程;
(6)-n<次數(shù)>:循環(huán)顯示的次數(shù)。
top執(zhí)行起來(lái)的效果如下:
前五行是系統(tǒng)整體的統(tǒng)計(jì)信息。第一行是任務(wù)隊(duì)列信息,第二行和第三行為進(jìn)程和CPU的信息,最后兩行為內(nèi)存信息。下面對(duì)一些比較重要的參數(shù)進(jìn)行說(shuō)明。
Load average:0.60,0.94,1.04。load average表示系統(tǒng)在過(guò)去1分鐘5分鐘15分鐘的任務(wù)隊(duì)列的平均長(zhǎng)度。這個(gè)值越大就表示系統(tǒng)CPU越繁忙。
Cpu(s):5.0%us(用戶空間占用的cpu百分百),3.9%sy(系統(tǒng)空間占用的cpu百分比),0.0%ni(用戶進(jìn)程空間內(nèi)改變過(guò)優(yōu)先級(jí)的用戶占用的cpu百分比),90.9%id(空閑cpu的百分比),0.2%wa(等待輸入輸出cpu的百分比)。
Mem:817280k buffers(用作內(nèi)核緩存的內(nèi)存量)。
Swap:磁盤交換區(qū)容量。
1.2 strace
strace可以跟蹤到一個(gè)進(jìn)程產(chǎn)生的系統(tǒng)調(diào)用,包含參數(shù)、返回值、執(zhí)行消耗的時(shí)間。
strace的常用的選項(xiàng)以及選項(xiàng)對(duì)應(yīng)的含義如下:
(1)-c 統(tǒng)計(jì)每一系統(tǒng)調(diào)用的所執(zhí)行的時(shí)間,次數(shù)和出錯(cuò)的次數(shù)等
(2)-f 跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程
(3)-t 在輸出中的每一行前加上時(shí)間信息
(4)-tt 在輸出中的每一行前加上時(shí)間信息(微妙級(jí))
(5)-T 顯示每一調(diào)用所耗的時(shí)間
(6)-e trace=set 只跟蹤指定的系統(tǒng)調(diào)用。例如:-e trace=open,close,read,write表示只跟蹤這四個(gè)系統(tǒng)調(diào)用。默認(rèn)的為set=all
(7)-e trace=file 只跟蹤有關(guān)文件操作的系統(tǒng)調(diào)用
(8)-e trace=process 只跟蹤有關(guān)進(jìn)程控制的系統(tǒng)調(diào)用
(9)-e trace=network 跟蹤與網(wǎng)絡(luò)有關(guān)的所有系統(tǒng)調(diào)用
(10)-e strace=signal 跟蹤所有與系統(tǒng)信號(hào)有關(guān)的 系統(tǒng)調(diào)用
(11)-e trace=ipc 跟蹤所有與進(jìn)程通訊有關(guān)的系統(tǒng)調(diào)用
(12)-o filename 將strace的輸出寫入文件filename -p pid 跟蹤指定的進(jìn)程pid
例如執(zhí)行 strace cat /dev/null,會(huì)得到如下輸出:
每一行都是一條系統(tǒng)調(diào)用,等號(hào)左邊是系統(tǒng)調(diào)用的函數(shù)名及其參數(shù),右邊是該調(diào)用的返回值。如果你知道你要找的是什么,你可以讓strace只跟蹤一些類型的系統(tǒng)調(diào)用。例如你需要看看在loadconfigure腳本里面執(zhí)行的程序里面系統(tǒng)調(diào)用ececve的調(diào)用情況,則只需要輸入這樣一條shell命令:strace -f -o loadconfigure-strace.txt -e execve ./loadconfigure
再例如,我們知道ActLogicSvr的進(jìn)程號(hào)是16789,則可以執(zhí)行strace -p 16789 -c來(lái)統(tǒng)計(jì)ActLogicSvr在某一段時(shí)間系統(tǒng)調(diào)用的統(tǒng)計(jì)情況。結(jié)果如下所示:
這里很清楚的告訴你調(diào)用了那些系統(tǒng)函數(shù),調(diào)用次數(shù)多少,消耗了多少時(shí)間等等這些信息,這個(gè)對(duì)我們分析一個(gè)程序來(lái)說(shuō)是非常有用的。
1.3 Perf
perf是Linux的性能調(diào)優(yōu)工具。perf工具的常用命令包括top,record,report等。
perf top命令用來(lái)顯示程序運(yùn)行的整體狀況。該命令主要用來(lái)觀察整個(gè)系統(tǒng)當(dāng)前的狀態(tài),比如可以通過(guò)查看該命令的輸出來(lái)查看當(dāng)前系統(tǒng)最耗時(shí)的內(nèi)核函數(shù)或某個(gè)用戶進(jìn)程。Perf stat的運(yùn)行效果如下:
perf record命令則用來(lái)記錄指定事件在程序運(yùn)行過(guò)程中的信息,而Perf report命令則用來(lái)報(bào)告基于前面record命令記錄的事件信息生成的程序運(yùn)行狀況報(bào)告。我們通常用命令perf record -g -p pid將進(jìn)程在命令運(yùn)行期間的各項(xiàng)指令運(yùn)行所占CPU的比例存在perf.data里面(-g表示記錄函數(shù)之間的調(diào)用關(guān)系)。再用perf report --call-graph --stdio將剛剛的統(tǒng)計(jì)結(jié)果展示出來(lái)。
perf record帶-g選項(xiàng)時(shí),perf report的運(yùn)行效果:
perf record不帶-g選項(xiàng)時(shí),perf report的運(yùn)行效果:
1.4 vmstat
vmstat是一個(gè)很全面的性能分析工具,可以觀察到系統(tǒng)的進(jìn)程狀態(tài)、內(nèi)存使用、虛擬內(nèi)存使用、磁盤的 IO、中斷、上下問(wèn)切換、CPU使用等。
vmstat的輸出如下:
procs:
- r:運(yùn)行隊(duì)列中進(jìn)程數(shù)量,這個(gè)值也可以判斷是否需要增加CPU。(長(zhǎng)期大于1)
- b:因?yàn)閕o處于阻塞狀態(tài)的進(jìn)程數(shù)。
memory:
-swap:使用虛擬內(nèi)存大小
-free:空閑物理內(nèi)存大小
-buff:用作緩沖的內(nèi)存大小
-cache:用作緩存的內(nèi)存大小
swap:
si:每秒從交換區(qū)寫到內(nèi)存的大小,由磁盤調(diào)入內(nèi)存
so:每秒寫入交換區(qū)的內(nèi)存大小,由內(nèi)存調(diào)入磁盤
io:
- bi:從塊設(shè)備讀入的數(shù)據(jù)總量(讀磁盤)(KB/s)
- bo:寫入到塊設(shè)備的數(shù)據(jù)總量(寫磁盤)(KB/s)
system:
- in:每秒產(chǎn)生的中斷次數(shù)
- cs:每秒產(chǎn)生的上下文切換次數(shù)
cpu:
- us:用戶進(jìn)程消耗的CPU時(shí)間百分比
- sy:內(nèi)核進(jìn)程消耗的CPU時(shí)間百分比
- wa:IO等待消耗的CPU時(shí)間百分比
- id:CPU處在空閑狀態(tài)時(shí)間百分比
2.網(wǎng)絡(luò)
2.1 netstat命令
netstat命令用來(lái)打印Linux中網(wǎng)絡(luò)系統(tǒng)的狀態(tài)信息,可讓你得知整個(gè)Linux系統(tǒng)的網(wǎng)絡(luò)情況。
netstat的常用的選項(xiàng)如下:
(1)-a(all)顯示所有選項(xiàng)
(2)-t(tcp)僅顯示tcp相關(guān)選項(xiàng)
(3)-u(udp)僅顯示udp相關(guān)選項(xiàng)
(4)-l(listen)僅列出有在Listen(監(jiān)聽(tīng))的服務(wù)狀態(tài)
(5)-p(program)顯示建立相關(guān)鏈接的程序名
(6)-r(route)顯示路由信息,路由表
(7)-e(extend)顯示擴(kuò)展信息
(8)-c 每隔一個(gè)固定時(shí)間,執(zhí)行該netstat命令。
在這里我們簡(jiǎn)單復(fù)習(xí)一下TCP三次握手和四次揮手的過(guò)程,便于下面解釋netstat中tcp的各種狀態(tài)。
TCP三次握手的過(guò)程如下:
(1)主動(dòng)連接端發(fā)送一個(gè)SYN包給被動(dòng)連接端;
(2)被動(dòng)連接端收到SYN包后,發(fā)送一個(gè)帶ACK的SYN包給主動(dòng)連接端。
(3)主動(dòng)連接端發(fā)送一個(gè)帶ACK標(biāo)志的包給被動(dòng)連接端,握手動(dòng)作完成。
TCP的四次揮手過(guò)程如下:
(1)主動(dòng)關(guān)閉端發(fā)送一個(gè)FIN包給被動(dòng)關(guān)閉端。
(2)被動(dòng)關(guān)閉端收到FIN包后,發(fā)送一個(gè)ACK包給主動(dòng)關(guān)閉端。
(3)被動(dòng)關(guān)閉端發(fā)送了ACK包后,再發(fā)送一個(gè)FIN包給主動(dòng)關(guān)閉端。
(4)主動(dòng)關(guān)閉端收到FIN包后,發(fā)送一個(gè)ACK包。當(dāng)被動(dòng)關(guān)閉端收到ACK后,四次揮手動(dòng)作完成,連接斷開(kāi)。
下面我們解釋一下netstat中tcp連接對(duì)應(yīng)的各種狀態(tài)。
(1)LISTEN:偵聽(tīng)狀態(tài),等待遠(yuǎn)程機(jī)器的連接請(qǐng)求。
(2)SYN_SEND:在TCP三次握手期間,主動(dòng)連接端發(fā)送了SYN包后,進(jìn)入SYN_SEND狀態(tài),等待對(duì)方的ACK包。
(3)SYN_RECV:在TCP三次握手期間,主動(dòng)接收端收到SYN包后,進(jìn)入SYN_RECV狀態(tài)。
(4)ESTABLISHED:完成TCP三次握手后,主動(dòng)連接端進(jìn)入ESTABLISHED狀態(tài)。此時(shí),TCP連接已經(jīng)建立,可以進(jìn)行通信。
(5)FIN_WAIT_1:在TCP四次揮手時(shí),主動(dòng)關(guān)閉端發(fā)送FIN包后,進(jìn)入FIN_WAIT_1狀態(tài)。
(6)FIN_WAIT_2:在TCP四次揮手時(shí),主動(dòng)關(guān)閉端收到ACK包后,進(jìn)入FIN_WAIT_2狀態(tài)。
(7)TIME_WAIT:在TCP四次揮手時(shí),主動(dòng)關(guān)閉端發(fā)送了ACK包之后,進(jìn)入TIME_WAIT狀態(tài),等待最多2MSL時(shí)間,讓被動(dòng)關(guān)閉端收到ACK包。
(8)CLOSING:在TCP四次揮手期間,主動(dòng)關(guān)閉端發(fā)送了FIN包后,沒(méi)有收到對(duì)應(yīng)的ACK包,卻收到了對(duì)方的FIN包,此時(shí)進(jìn)入CLOSING狀態(tài)。
(9)CLOSE_WAIT:在TCP四次揮手期間,被動(dòng)關(guān)閉端收到FIN包后,進(jìn)入CLOSE_WAIT狀態(tài)。
(10)LAST_ACK:在TCP四次揮手時(shí),被動(dòng)關(guān)閉端發(fā)送FIN包后,進(jìn)入LAST_ACK狀態(tài),等待對(duì)方的ACK包。
netstat -te(顯示出所有的tcp連接)執(zhí)行起來(lái)的效果如下:
netstat的常用方法:
(1)netstat -p | grep 19626:得到進(jìn)程號(hào)19626的進(jìn)程所打開(kāi)的所有端口
(2)netstat -tpl:查看當(dāng)前tcp監(jiān)聽(tīng)端口, 需要顯示監(jiān)聽(tīng)的程序名。
(3)netstat -c 2:隔兩秒執(zhí)行一次netstat,持續(xù)輸出
2.2 lsof
lsof命令用于查看進(jìn)程開(kāi)打的文件,打開(kāi)文件的進(jìn)程,進(jìn)程打開(kāi)的端口(TCP、UDP)。在linux環(huán)境下,任何事物都以文件的形式存在,通過(guò)文件不僅僅可以訪問(wèn)常規(guī)數(shù)據(jù),還可以訪問(wèn)網(wǎng)絡(luò)連接和硬件。在使用TCP的UDP的時(shí)候,系統(tǒng)在后臺(tái)都為該應(yīng)用程序分配了一個(gè)文件描述符。無(wú)論這個(gè)文件的本質(zhì)如何,該文件描述符為應(yīng)用程序與基礎(chǔ)操作系統(tǒng)之間的交互提供了通用接口。
lsof的使用示例如下:
輸出的各項(xiàng)的含義如下:
COMMAND:進(jìn)程的名稱
PID:進(jìn)程標(biāo)識(shí)符
USER:進(jìn)程所有者
FD:文件描述符,應(yīng)用程序通過(guò)文件描述符識(shí)別該文件。如cwd、txt等
TYPE:文件類型,如DIR、REG等
DEVICE:指定磁盤的名稱
SIZE:文件的大小
NODE:索引節(jié)點(diǎn)(文件在磁盤上的標(biāo)識(shí))
NAME:打開(kāi)文件的確切名稱
Lsof的常用方法:
(1)lsof abc.txt:查看所有打開(kāi)了文件abc.txt的進(jìn)程。
(2)lsof -p pid:顯示進(jìn)程打開(kāi)的所有的文件。
2.3 tcpdump
tcpdump可以將網(wǎng)絡(luò)中傳送的數(shù)據(jù)包完全截獲下來(lái)提供分析。它支持針對(duì)網(wǎng)絡(luò)層、協(xié)議、主機(jī)、網(wǎng)絡(luò)或端口的過(guò)濾,并提供and、or、not等邏輯語(yǔ)句來(lái)幫助你去掉無(wú)用的信息。
tcpdump的常用參數(shù):
(1)-nn,直接以 IP 及 Port Number 顯示,而非主機(jī)名與服務(wù)名稱。
(2)-i,后面接要「監(jiān)聽(tīng)」的網(wǎng)絡(luò)接口,例如 eth0, lo, ppp0 等等的接口。
(3)-w,如果你要將監(jiān)聽(tīng)所得的數(shù)據(jù)包數(shù)據(jù)儲(chǔ)存下來(lái),用這個(gè)參數(shù)就對(duì)了。后面接文件名。
(4)-c,監(jiān)聽(tīng)的數(shù)據(jù)包數(shù),如果沒(méi)有這個(gè)參數(shù), tcpdump 會(huì)持續(xù)不斷的監(jiān)聽(tīng),直到用戶輸入 [ctrl]-c 為止。
(5)-A,數(shù)據(jù)包的內(nèi)容以 ASCII 顯示,通常用來(lái)捉取 WWW 的網(wǎng)頁(yè)數(shù)據(jù)包資料。
(6)-e,使用資料連接層 (OSI 第二層) 的 MAC 數(shù)據(jù)包數(shù)據(jù)來(lái)顯示。
(7)-q,僅列出較為簡(jiǎn)短的數(shù)據(jù)包信息,每一行的內(nèi)容比較精簡(jiǎn)。
(8)-X,可以列出十六進(jìn)制 (hex) 以及 ASCII 的數(shù)據(jù)包內(nèi)容,對(duì)于監(jiān)聽(tīng)數(shù)據(jù)包內(nèi)容很有用。
(9)-r,從后面接的文件將數(shù)據(jù)包數(shù)據(jù)讀出來(lái)。那個(gè)「文件」是已經(jīng)存在的文件,并且這個(gè)「文件」是由 -w 所制作出來(lái)的。
tcpdump的常見(jiàn)用法:
(1)tcpdump -i eth1 host ***.***.***.***:抓取所有經(jīng)過(guò) eth1,目的或源地址是***.***.***.***的網(wǎng)絡(luò)數(shù)據(jù)。
(2)tcpdump -i eth1 dst host ***.***.***.***:抓取所有經(jīng)過(guò) eth1,目的地址是***.***.***.***的網(wǎng)絡(luò)數(shù)據(jù)。
(3)tcpdump -i eth1 src host ***.***.***.***:抓取所有經(jīng)過(guò) eth1,源地址是***.***.***.***的網(wǎng)絡(luò)數(shù)據(jù)。
(4)tcpdump -i eth1 port 36000:抓取所有經(jīng)過(guò) eth1,目的端口或源端口是36000的網(wǎng)絡(luò)數(shù)據(jù)。
(5)tcpdump -i eth1 src port 36000:抓取所有經(jīng)過(guò) eth1,源端口是36000的網(wǎng)絡(luò)數(shù)據(jù)。
(6)tcpdump -i eth1 dst port 36000:抓取所有經(jīng)過(guò) eth1,目的端口是36000的網(wǎng)絡(luò)數(shù)據(jù)。
(7)tcpdump -i eth1 'src host ***.***.***.*** && src port 36000':抓取所有經(jīng)過(guò) eth1,目的地址是10.136.12.1且目的端口是36000的網(wǎng)絡(luò)數(shù)據(jù)。
(8)在10.136.12.1機(jī)器上我們通過(guò)top知道了ActLogicSvr的進(jìn)程id為16789。然后通過(guò)netstat -ap | grep 16789得到ActLogicSvr監(jiān)聽(tīng)的端口是10014。如下圖所示:
然后我們通過(guò) tcpdump -i eth1 'port 10014' -xxx抓取通過(guò)10014端口的所有的包。我們通過(guò)模擬接口測(cè)試的方法給ActLogicSvr發(fā)一條請(qǐng)求。抓到的包結(jié)果如下:
從抓到的包上我們可以清楚的看到tcp連接建立的三次握手到數(shù)據(jù)傳輸?shù)絫cp連接斷開(kāi)四次揮手的過(guò)程(前三個(gè)數(shù)據(jù)包是三次握手的過(guò)程,最后四個(gè)數(shù)據(jù)包是四次揮手的過(guò)程,中間的為數(shù)據(jù)傳輸所產(chǎn)生的網(wǎng)絡(luò)數(shù)據(jù)包)。
3 內(nèi)存
3.1 valgrind
valgrind 是在Linux程序中廣泛使用的調(diào)試應(yīng)用程序。它尤其擅長(zhǎng)發(fā)現(xiàn)內(nèi)存管理的問(wèn)題,可以檢查程序運(yùn)行時(shí)的內(nèi)存泄漏問(wèn)題等。我們?cè)谑褂胿algrind時(shí)也主要用到它的內(nèi)存泄漏檢測(cè)功能,即memcheck功能。它檢查所有對(duì)內(nèi)存的讀/寫操作,并截取所有的malloc/new/free/delete調(diào)用。因此memcheck工具能夠探測(cè)到以下問(wèn)題:
(1)使用未初始化的內(nèi)存
(2)讀/寫已經(jīng)被釋放的內(nèi)存
(3)讀/寫內(nèi)存越界
(4)讀/寫不恰當(dāng)?shù)膬?nèi)存棧空間
(5)內(nèi)存泄漏
(6)使用malloc/new/new[]和free/delete/delete[]不匹配。
(7)src和dst的重疊valgrind的可選的參數(shù)以及對(duì)應(yīng)的含義如下所示:
(1)-version 顯示valgrind內(nèi)核的版本,每個(gè)工具都有各自的版本。
(2)q –quiet 安靜地運(yùn)行,只打印錯(cuò)誤信。
(3)v –verbose 更詳細(xì)的信息, 增加錯(cuò)誤數(shù)統(tǒng)計(jì)。
(4)-trace-children=no|yes 跟蹤子線程
(5)-track-fds=no|yes 跟蹤打開(kāi)的文件描述
(6)-time-stamp=no|yes 增加時(shí)間戳到LOG信息
(7)-log-fd= 輸出LOG到描述符文
(8)-log-file= 將輸出的信息寫入到filename.PID的文件里,PID是運(yùn)行程序的進(jìn)行ID
(9)-log-file-exactly= 輸出LOG信息到 file
(10)-log-file-qualifier= 取得環(huán)境變量的值來(lái)做為輸出信息的文件名。
(11)-log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port
LOG信息輸出:
(1)-xml=yes 將信息以xml格式輸出,只有memcheck可用
(2)-num-callers= show callers in stack traces [12]
(3)-error-limit=no|yes 如果太多錯(cuò)誤,則停止顯示新錯(cuò)誤? [yes]
(4)-error-exitcode= 如果發(fā)現(xiàn)錯(cuò)誤則返回錯(cuò)誤代碼 [0=disable]
(5)-db-attach=no|yes 當(dāng)出現(xiàn)錯(cuò)誤,valgrind會(huì)自動(dòng)啟動(dòng)調(diào)試器gdb。[no]
(6)-db-command=
啟動(dòng)調(diào)試器的命令行選項(xiàng)[gdb -nw %f %p]適用于Memcheck工具的相關(guān)選項(xiàng):
(1)--leak-check=no|summary|full 要求對(duì)leak給出詳細(xì)信息? [summary]
(2)--leak-resolution=low|med|high how much bt merging in leak check [low]
(3)--show-reachable=no|yes show reachable blocks in leak check? [no]
示例:valgrind --leak-check=full /usr/local/app/taf/tafnode/data/TenFortune.WeChatProxySvr/bin/WeChatProxySvr --config=/usr/local/app/taf/tafnode/data/TenFortune.WeChatProxySvr/conf/TenFortune.WeChatProxySvr.config.conf -trace-child=yes。執(zhí)行的結(jié)果:
4 磁盤
4.1 iotop
iotop命令是一個(gè)用來(lái)監(jiān)視磁盤I/O使用狀況的top類工具。iotop具有與top相似的UI,其中包括PID、用戶、I/O、進(jìn)程等相關(guān)信息。Linux下的IO統(tǒng)計(jì)工具如iostat,nmon等大多數(shù)是只能統(tǒng)計(jì)到per設(shè)備的讀寫情況,如果你想知道每個(gè)進(jìn)程是如何使用IO的就比較麻煩,使用iotop命令可以很方便的查看。
iostat命令選項(xiàng):
-o:只顯示有io操作的進(jìn)程
-n NUM:顯示NUM次,主要用于非交互式模式。
-d SEC:間隔SEC秒顯示一次。
-p PID:監(jiān)控的進(jìn)程pid。
-u USER:監(jiān)控的進(jìn)程用戶。
iotop的執(zhí)行效果:
?
評(píng)論
查看更多