之前組內(nèi)一位大佬分享了一些關(guān)于系統(tǒng)性能優(yōu)化方面的干貨,這里我將它整理成文并且加入自己平時(shí)常用的一些工具和技巧印蓖。由于關(guān)于系統(tǒng)性能優(yōu)化涉及的內(nèi)容非常多,我會(huì)分幾篇文章來分享。這次分享下定位系統(tǒng)層面問題
的常用方法数尿。
系統(tǒng)性能定義
- Throughout 吞吐量 (系統(tǒng)每秒鐘可以處理的請求數(shù))
- Latency 延遲 (系統(tǒng)處理一個(gè)請求的延遲)
- Usage 資源利用率
吞吐量和延遲的關(guān)系
- 吞吐量越高,延遲會(huì)越大惶楼。因?yàn)檎埱罅窟^大右蹦,系統(tǒng)太繁忙,所以響應(yīng)時(shí)間會(huì)降低歼捐。
- 延遲越小何陆,能支持的吞吐量會(huì)越高。因?yàn)檠舆t短說明處理速度快豹储,就可以處理更多的請求贷盲。
異步化可以提高系統(tǒng)的吞吐量的靈活性,但是不會(huì)獲得更快的響應(yīng)時(shí)間剥扣。
系統(tǒng)性能壓測的常用工具
tcpdump
1. 常用參數(shù):
-i:指定需要的網(wǎng)
-s:抓取數(shù)據(jù)包時(shí)默認(rèn)抓取長度為68字節(jié)巩剖,加上-s 0后可以抓到完整的數(shù)據(jù)包
-w:監(jiān)聽的數(shù)據(jù)包寫入指定的文件
2. 示例
tcpdump -i eth1 host 10.1.1.1 // 抓取所有經(jīng)過eth1,目的或源地址是10.1.1.1的網(wǎng)絡(luò)數(shù)據(jù)包
tcpdump -i eth1 src host 10.1.1.1 // 源地址
tcpdump -i eth1 dst host 10.1.1.1 // 目的地址
如果想使用wireshark分析tcpdump的包钠怯,需要加上是 -s 參數(shù):
tcpdump -i eth0 tcp and port 80 -s 0 -w traffic.pcap
tcpcopy——線上引流壓測
tcpcopy是一種請求復(fù)制工具佳魔,用于實(shí)時(shí)和離線回放,它可以將線上流量拷貝到測試機(jī)器晦炊,實(shí)時(shí)模擬線上的真實(shí)環(huán)境鞠鲜,達(dá)到程序不上線的情況下承擔(dān)線上真實(shí)流量的測試宁脊。實(shí)戰(zhàn)演習(xí)的必備工具。
a. tcpdump錄制pace文件
tcpdump -i eth0 -w online.pcap tcp and port 80
b. 流量回放
tcpcopy -x 80-10.1.x.x:80 -i traffic.pcap
tcpcopy -x 80-10.1.x.x:80 -a 2 -i traffic.pcap // 離線回放加速2倍
c. 引流模式
tcpcopy -x 80-10.1.x.x:80 -r 20 // 20%引流
tcpcopy -x 80-10.1.x.x:80 -n 3 // 放大三倍引流
wrk & ApacheBench & Jmeter & webbench
個(gè)人非常推薦wrk镊尺,輕量且壓測結(jié)果準(zhǔn)確朦佩,結(jié)合Lua腳本可以支持更復(fù)雜的測試場景。
壓測示例:4個(gè)線程來模擬1000個(gè)并發(fā)連接庐氮,整個(gè)測試持續(xù)30秒语稠,連接超時(shí)30秒,打印出請求的延遲統(tǒng)計(jì)信息弄砍。
> wrk -t4 -c1000 -d30s -T30s --latency http://www.baidu.com
Running 30s test @ http://www.baidu.com
4 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.71s 3.19s 26.51s 89.38%
Req/Sec 15.83 10.59 60.00 66.32%
Latency Distribution
50% 434.52ms
75% 1.70s
90% 5.66s
99% 14.38s
1572 requests in 30.09s, 26.36MB read
Requests/sec: 52.24
Transfer/sec: 0.88MB
更多參數(shù)幫助信息:
> wrk --help
Usage: wrk <options> <url>
Options:
-c, --connections <N> Connections to keep open
-d, --duration <T> Duration of test
-t, --threads <N> Number of threads to use
-s, --script <S> Load Lua script file
-H, --header <H> Add header to request
--latency Print latency statistics
--timeout <T> Socket/request timeout
-v, --version Print version details
Numeric arguments may include a SI unit (1k, 1M, 1G)
Time arguments may include a time unit (2s, 2m, 2h)
定位性能瓶頸
可以從以下幾個(gè)方面衡量系統(tǒng)的性能:
- 應(yīng)用層面
- 系統(tǒng)層面
- JVM層面
- Profiler
應(yīng)用層面
應(yīng)用層面的性能指標(biāo):
- QPS
- 響應(yīng)時(shí)間仙畦,95、99線等音婶。
- 成功率
系統(tǒng)層面
系統(tǒng)層面指標(biāo)有Cpu慨畸、內(nèi)存、磁盤衣式、網(wǎng)路等寸士,推薦用一個(gè)犀利的命令查詢系統(tǒng)性能情況:
dstat -lcdngy
dstat非常強(qiáng)大,可以實(shí)時(shí)的監(jiān)控cpu碴卧、磁盤弱卡、網(wǎng)絡(luò)、IO住册、內(nèi)存等使用情況婶博。
- 安裝方法
yum install -y dstat
- 功能說明
-c:顯示CPU系統(tǒng)占用,用戶占用荧飞,空閑凡人,等待,中斷叹阔,軟件中斷等信息挠轴。
-C:當(dāng)有多個(gè)CPU時(shí)候,此參數(shù)可按需分別顯示cpu狀態(tài)耳幢,例:-C 0,1 是顯示cpu0和cpu1的信息忠荞。
-d:顯示磁盤讀寫數(shù)據(jù)大小。 -D hda,total:include hda and total帅掘。
-n:顯示網(wǎng)絡(luò)狀態(tài)。 -N eth1,total:有多塊網(wǎng)卡時(shí)堂油,指定要顯示的網(wǎng)卡修档。
-l:顯示系統(tǒng)負(fù)載情況。
-m:顯示內(nèi)存使用情況府框。
-g:顯示頁面使用情況吱窝。
-p:顯示進(jìn)程狀態(tài)。
-s:顯示交換分區(qū)使用情況。
-S:類似D/N院峡。
-r:I/O請求情況兴使。
-y:系統(tǒng)狀態(tài)。
--ipc:顯示ipc消息隊(duì)列照激,信號等信息发魄。
--socket:用來顯示tcp udp端口狀態(tài)。
-a:此為默認(rèn)選項(xiàng),等同于-cdngy。
-v:等同于 -pmgdsc -D total医男。
--output 文件:此選項(xiàng)也比較有用嗽仪,可以把狀態(tài)信息以csv的格式重定向到指定的文件中,以便日后查看飞盆。例:dstat --output /root/dstat.csv & 此時(shí)讓程序默默的在后臺(tái)運(yùn)行并把結(jié)果輸出到/root/dstat.csv文件中。
Cpu
-
使用率:Cpu是最重要的資源,如果CPU在等待嵌削,也會(huì)導(dǎo)致Cpu高使用率。
CPU利用率 = 1 - 程序占用cpu時(shí)間/程序總的運(yùn)行時(shí)間
-
用戶時(shí)間/內(nèi)核時(shí)間:大致判斷應(yīng)用是計(jì)算密集型還是IO密集型望艺。
CPU花在用戶態(tài)代碼的時(shí)間稱為用戶時(shí)間苛秕,而執(zhí)行內(nèi)核態(tài)代碼的時(shí)間稱為內(nèi)核時(shí)間。內(nèi)核時(shí)間主要包括系統(tǒng)調(diào)用荣茫,內(nèi)核線程和中斷的時(shí)間想帅。當(dāng)在整個(gè)系統(tǒng)范圍內(nèi)進(jìn)行測量時(shí),用戶時(shí)間和內(nèi)核時(shí)間之比揭示了運(yùn)行的負(fù)載類型啡莉。計(jì)算密集型應(yīng)用會(huì)把大量時(shí)間花在用戶態(tài)代碼上港准,用戶時(shí)間/內(nèi)核時(shí)間之比接近99/1。這樣的例子有圖像處理咧欣,數(shù)據(jù)分析等浅缸。I/O密集型應(yīng)用的系統(tǒng)調(diào)用頻率較高,通過執(zhí)行內(nèi)核代碼進(jìn)行I/O操作魄咕。一個(gè)進(jìn)行網(wǎng)絡(luò)I/O的Web服務(wù)器的用戶/內(nèi)核時(shí)間比大約為70/30衩椒。
負(fù)載load:在特定時(shí)間間隔內(nèi)運(yùn)行隊(duì)列中的平均進(jìn)程數(shù)。每個(gè)CPU都有一個(gè)運(yùn)行隊(duì)列哮兰,隊(duì)列里存放著已經(jīng)就緒毛萌,等待被CPU執(zhí)行的線程。
理想狀態(tài)下喝滞,希望負(fù)載平均值小于等于Cpu核數(shù)阁将。
Cpu使用率和load的區(qū)別:
- 負(fù)載均值用來估量CPU利用率的發(fā)展趨勢,而不是某一時(shí)刻的狀況右遭。
- 負(fù)載均值包括所有CPU的需求做盅,而不僅僅是在測量時(shí)活躍的缤削。
磁盤
磁盤空間:沒有空間會(huì)導(dǎo)致程序無法啟動(dòng)或者報(bào)錯(cuò)。
du -sh //查看當(dāng)前文件夾下所有文件大小
df -hl //以磁盤分區(qū)為單位查看文件系統(tǒng)
有時(shí)候linux服務(wù)器的系統(tǒng)日志文件過大導(dǎo)致磁盤使用率過高吹榴,推薦兩種清理方式:
sudo /dev/null > /var/log/**.log //刪除指定的較大日志文件亭敢,速度快
sudo find /var/log/ -type f -mtime +30 -exec rm -f {} \ //刪除30天之前的日志文件
磁盤權(quán)限:沒有權(quán)限會(huì)導(dǎo)致程序無法啟動(dòng)或者報(bào)錯(cuò)。
ll /yourdir
磁盤性能測試
dd if=/dev/zero of=output.file bs=10M count=1
io吞吐图筹、iowait
這里重點(diǎn)說下這兩個(gè)因素帅刀,大量的磁盤讀寫以及過高的iowait往往意味著磁盤可能是瓶頸。實(shí)際上iowait并不能反映磁盤成為性能瓶頸婿斥,它實(shí)際測量的是cpu的時(shí)間:
%iowait = (cpu idle time)/(all cpu time)
所以唯一定位磁盤成為性能瓶頸的直接方法還是看read/write時(shí)間
劝篷。下面我們著重介紹下如何定位io問題。
a. 宏觀確定是否是io的問題:top命令民宿,可以從Cpu這一行看出浪費(fèi)在I/O Wait上的CPU百分比娇妓;數(shù)值越高代表越多的CPU資源在等待I/O權(quán)限。
b. 確定具體磁盤問題:iostat
%util直觀地反應(yīng)可哪一塊磁盤正在被寫入活鹰,反應(yīng)了設(shè)備的繁忙程度哈恰。每毫秒讀寫請求(rrqm/s wrqm/s)以及每秒讀寫(r/s w/s)對排查問題也提供了很多有用的信息。
c. 確定具體進(jìn)程:簡單粗暴的iotop直觀地反映了哪些進(jìn)程是導(dǎo)致io問題的罪魁禍?zhǔn)住?/p>
d. ps判斷進(jìn)程是否等待IO一樣強(qiáng)大
眾所周知志群,ps命令為我們提供了內(nèi)存着绷、cpu以及進(jìn)程狀態(tài)等信息,根據(jù)進(jìn)程狀態(tài)可以很容易查到正在等待IO的進(jìn)程信息锌云。
這里簡單說下linux進(jìn)程的幾種狀態(tài):
- R (TASK_RUNNING)荠医,可執(zhí)行狀態(tài)。
- S (TASK_INTERRUPTIBLE)桑涎,可中斷的睡眠狀態(tài)彬向。
- D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)攻冷。
- T (TASK_STOPPED or TASK_TRACED)娃胆,暫停狀態(tài)或跟蹤狀態(tài)。
- Z (TASK_DEAD – EXIT_ZOMBIE)等曼,退出狀態(tài)里烦,進(jìn)程成為僵尸進(jìn)程。
- X (TASK_DEAD – EXIT_DEAD)禁谦,退出狀態(tài)胁黑,進(jìn)程即將被銷毀。
其中等待I/O的進(jìn)程狀態(tài)一般是"uninterruptible sleep"即D狀態(tài)州泊,D狀態(tài)以及R狀態(tài)進(jìn)程算為運(yùn)行隊(duì)列之中
丧蘸,所以D狀態(tài)進(jìn)程過多也會(huì)導(dǎo)致系統(tǒng)load偏高,有興趣可以看下linux load的計(jì)算原理拥诡。
查看D狀態(tài)進(jìn)程:
> for x in `seq 1 1 10`; do ps -eo state,pid,cmd | grep "^D"; echo "--------"; sleep 5; done
D 13389 /usr/libexec/gcc/x86_64-redhat-linux/4.4.7/cc1 -quiet -I../../include/cat -I../ -I. -dD message_sender.c -quiet -dumpbase message_sender.c -mtune=generic -auxbase message_sender -ggdb3 -O2 -O0 -o /tmp/ccivsNPE.s
根據(jù)proc偽文件系統(tǒng)獲取io相關(guān)信息:
> cat /proc/pid/io
rchar: 548875497
wchar: 270446556
syscr: 452342
syscw: 143986
read_bytes: 253100032
write_bytes: 24645632
cancelled_write_bytes: 3801088
e. 確定哪個(gè)文件頻繁讀寫:lsof -p pid
網(wǎng)絡(luò)
1. nestat
netstat -nt 查看tcp相關(guān)連接狀態(tài)触趴、連接數(shù)以及發(fā)送隊(duì)列和接收隊(duì)列
關(guān)于tcp的狀態(tài)需要大家熟悉三次握手和四次揮手的過程,這里先列出tcp的全部狀態(tài)渴肉。
客戶端:SYN_SENT冗懦、FIN_WAIT1、FIN_WAIT2仇祭、CLOSING披蕉、TIME_WAIT
服務(wù)端:LISTEN、SYN_RCVD乌奇、CLOSE_WAIT没讲、LAST_ACK
Common:ESTABLISHED、CLOSED
Tcp狀態(tài)變化圖(摘自網(wǎng)絡(luò)):
關(guān)于tcp狀態(tài)的幾點(diǎn)說明:
- 正常的連接應(yīng)該是ESTABLISHED狀態(tài)礁苗,如果存在大量的SYN_SENT的連接爬凑,則需要看下防火墻規(guī)則。
如果Recv-Q或者Send-Q持續(xù)有大量包存在试伙,意味著連接存在瓶頸或者程序存在bug嘁信。
2. 一些其他常用技巧
關(guān)于netstat還有很多有用的技巧,這里列出平時(shí)比較常用的:
netstat -nap | grep port 顯示使用該端口的所有進(jìn)程id
netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn 查詢?nèi)繝顟B(tài)并排序
awk '{print $1}' access.log |sort|uniq -c|sort -nr|head -10 分析access.log獲取訪問做多的top n的ip地址
netstat -nat | grep "10.1.1.1:8080" |awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -20 連接某服務(wù)器最多的top n的ip地址
netstat -s 如果重傳的包持續(xù)增加疏叨,那么很大可能網(wǎng)卡存在問題
JVM
定位問題的殺手锏——線程堆棧
1. 獲取線程堆棧的步驟:
ps -ef | grep java
jstack <pid> > /tmp/jstack.<pid>
小技巧:jstack信息是某個(gè)時(shí)刻的堆棧信息潘靖,有時(shí)間僅僅一個(gè)jstack并不能分析出問題所在,可以適當(dāng)多幾次jstack蚤蔓,然后進(jìn)行對比分析卦溢。
2. 如何從線程堆棧中找到本地線程對應(yīng)的id
nid=native thread id,特殊的是nid使用十六進(jìn)制標(biāo)識秀又,本地線程id是十進(jìn)制標(biāo)識单寂,所以通過進(jìn)制換算就可以講兩者對應(yīng)起來。
16進(jìn)制和10進(jìn)制的互換:
printf %d 0x1b40
printf "0x%x" 6976
3. Cpu消耗高的分析方法
a. 找出對應(yīng)的java進(jìn)程pid:
ps -ef | grep java
b. 找出java進(jìn)程中最消耗cpu的線程:
top -H -p <pid>
- 將找出的線程id轉(zhuǎn)換為16進(jìn)制
- jstack獲取java的線程堆棧
- 根據(jù)16進(jìn)制的id從線程堆棧中找到相關(guān)的堆棧信息
說明:線程堆棧中可以看出對應(yīng)線程執(zhí)行的是Java代碼還是Native method
找不到對應(yīng)的線程堆棧涮坐?
- 執(zhí)行的Native method是重新創(chuàng)建的線程凄贩。
- 代碼bug,堆內(nèi)存耗完袱讹,jvm不斷執(zhí)行full gc疲扎。
- jvm自身bug??。
垃圾收集的統(tǒng)計(jì)信息——查看Gc原因
jstat -gccause用于查看垃圾收集的統(tǒng)計(jì)信息捷雕,若有發(fā)生垃圾回收椒丧,還會(huì)顯示最后一次以及當(dāng)前發(fā)生垃圾回收的原因,它比-gcutil會(huì)多出最后一次垃圾回收的原因以及當(dāng)前正在發(fā)生的垃圾回收的原因救巷。
jstat -gccause pid 1234
轉(zhuǎn)載請注明出處壶熏,歡迎關(guān)注我的公眾號:亞普的技術(shù)輪子