服務(wù)出現(xiàn)明顯的變慢,該如何診斷處理?
在日常工作中,應(yīng)用出現(xiàn)性能問題是不可避免的,絕大部分公司都沒有專門的性能團(tuán)隊(duì),出現(xiàn)問題還是需要我們自己去排查處理,所以掌握基本的性能知識(shí)和技能就顯得很有必要,也是開發(fā)工程師進(jìn)階的必要條件,能否快準(zhǔn)狠的定位解決問題,也是對(duì)知識(shí)、技能和能力的檢驗(yàn)。
今天我們來(lái)討論的問題是,服務(wù)出現(xiàn)明顯的變慢,該如何診斷處理?
首先我們要確定服務(wù)是突然變慢還運(yùn)行一段時(shí)間后觀察到變慢?類似的變慢是經(jīng)常出現(xiàn)還是偶發(fā)的?還有對(duì)慢的定義是什么?是否可以理解為系統(tǒng)對(duì)其他方面的請(qǐng)求的延時(shí)變長(zhǎng)?
在理清楚問題的癥狀后,更有利于分析問題的具體原因,大概有以下思路:
- 檢查應(yīng)用本身的錯(cuò)誤日志,看是否在系統(tǒng)變慢的時(shí)候存在大量錯(cuò)誤日志,來(lái)判斷是否出現(xiàn)意外的程序錯(cuò)誤。對(duì)于分布式系統(tǒng),很多公司都會(huì)有日志、性能監(jiān)控系統(tǒng),使用一些Java診斷工具也可以用于診斷,監(jiān)控應(yīng)用是否大量出現(xiàn)某種類型的異常。
- 監(jiān)控Java服務(wù)本身,查看GC日志里面是否觀察到頻繁的Full GC等,可以利用jstat等工具獲取內(nèi)存使用的統(tǒng)計(jì)信息,利用jstack等工具檢查是否出現(xiàn)死鎖等。
- 如果還不能定位問題,可以使用性能檢測(cè)工具Profiling,因?yàn)樗鼘?duì)系統(tǒng)是有侵入性的,非必要,不建議在生產(chǎn)系統(tǒng)進(jìn)行。
- 定位到問題,采取相應(yīng)的補(bǔ)救措施,然后驗(yàn)證是否解決,如果沒有解決,重復(fù)上面的操作。
接下來(lái)我們來(lái)了解一下業(yè)內(nèi)廣泛的性能分析方法論。方法論總結(jié)為兩類:
- 自上而下。從應(yīng)用頂層,逐步深入到具體的不同模塊,或者更近一步的技術(shù)細(xì)節(jié)單元,找到可能的問題和解決方法,這也是最常見的性能分析方法,也是大部分人的選擇。
- 自下而上。從類似CPU的這種硬件底層,判斷類似Cache-Miss之類的問題和調(diào)優(yōu)機(jī)會(huì),出發(fā)點(diǎn)是指令級(jí)別優(yōu)化。這往往門檻比較高,需要掌握專業(yè)的技能,還得專業(yè)的工具配合,一般出現(xiàn)在新平臺(tái)移植或者追求極致性能的時(shí)候才會(huì)進(jìn)行。
我們重點(diǎn)看第一種,自上而下。各個(gè)階段的思路以及使用的工具等。
分析系統(tǒng)的性能,我們常從CPU、內(nèi)存和IO等入手,這幾點(diǎn)是重點(diǎn)關(guān)注項(xiàng)。對(duì)于CPU,如果是Linux環(huán)境,可以先用top命令查看負(fù)載情況:
可以看到,平均負(fù)載的三個(gè)值并不高,也沒有升高的跡象,可以先不特別關(guān)注,接下來(lái)分析最耗費(fèi)CPU的Java線程,步驟如下:
利用top命令獲取相應(yīng)的pid,-H代表thread模式,也可以配合grep命令更精確定位。
top -H
然后轉(zhuǎn)換成16進(jìn)制。
printf "%x" your_pid
最后利用jstack獲取的線程棧,對(duì)比相應(yīng)的ID即可。也可以用vmstat,查看上下文切換的數(shù)量,比如指定時(shí)間間隔為1,收集20次
vmstat -1 -20
如果上下文切換非常高,并且系統(tǒng)中高很多,就表明可能存在不合理的線程調(diào)度導(dǎo)致的,可以用pidstat進(jìn)一步分析定位。
除了CPU,內(nèi)存和IO也有很多注意事項(xiàng):
- 利用free之類查看內(nèi)存的使用情況。
- 進(jìn)一步判斷 swap 使用情況,top命令輸出中Virt作為虛擬內(nèi)存使用量,就是物理內(nèi)存(Res)和 swap 求和,所以可以反推 swap 使用。顯然,JVM 是不希望發(fā)生大量的 swap 使用的。
- 對(duì)于 IO 問題,既可能發(fā)生在磁盤IO,也可能是網(wǎng)絡(luò)IO。例如,利用iostat等命令有助于判斷磁盤的健康狀況。