1. 程式人生 > >深入理解JVM——效能監控工具(七)

深入理解JVM——效能監控工具(七)

前言

工欲善其事必先利其器,效能優化和故障排查在我們大都數人眼裡是件比較棘手的事情,一是需要具備一定的原理知識作為基礎,二是需要掌握排查問題和解決問題的流程、方法。本文就將介紹利用效能監控工具,幫助開發者更快更準的找到問題產生的根源。本文分為三部分,第一部分將介紹在Linux環境下的常用監控工具,第二部分介紹Windows環境下的監控工具,第三部分將通過一個案例,介紹利用這些監控工具一步一步找出java應用程式的問題。

Linux環境下的監控工具

需要先宣告的是,下面介紹的部分工具其實在Liunx環境、Windows環境下都可以使用,只不過在不同的環境下使用什麼工具更合適。

下面我們想象這麼一個場景:有一天運維人員看到生產環境下的伺服器負載升高、CPU飆升,記憶體佔用增大,請問接下來他該怎麼辦?可能有人會說,那就找到負載升高、CPU飆升。。的原因啊,如果是應用程式造成的就把它kill掉。如果採用這種方法,問題可能會短時間解決,但帶來的問題是應用在一段時間不可用,並且我們沒有找到問題發生的根源,下次重啟後,問題依然會產生。那麼如果出現類似的問題,嚴格的排查流程是怎樣的呢?在回答這個問題之前,我們先了解一下Linux上常用的幾個監控工具:

uptime

[[email protected]_template ~]# uptime 10:31:42 up 4 days, 1:01, 1 user,load average: 0.02, 0.02, 0.05
10:31:42    //當前系統時間
up 4 days, 1:01 //持續執行時間,時間越大,說明你的機器越穩定。 
1 user  //使用者連線數,是總連線數而不是使用者數 
load average: 0.02, 0.02, 0.05  //系統平均負載,統計最近1,5,15分鐘的系統平均負載
該命令將顯示目前伺服器持續執行的時間,以及負載情況。

通過這個命令,可以最簡便的看出系統當前基本狀態資訊,這裡面最有用是負載指標

,如果你還想檢視當前系統的CPU/記憶體以及相關的程序狀態,可以使用TOP命令。

TOP

使用TOP命令檢視當前系統的CPU/記憶體以及相關的程序狀態 通過TOP命令可以詳細看出當前系統的CPU、記憶體、負載以及各程序狀態(PID、程序佔用CPU、記憶體、使用者)等。從上面的結果看出該系統上安裝了MySQL、java,可以看到他們各自的程序ID,假如這時Java程序佔用較高的CPU和記憶體,那麼你就要留心了,如果程式中沒有計算量特別大、佔用記憶體特別多的程式碼,可能你的java程式出現了未知的問題,可以根據程序ID做進一步的跟蹤。除了通過TOP命令找到程序資訊以外,還可以通過jdk自帶的工具JPS直接找到java程式的程序號。

JPS

在這裡插入圖片描述 可以看到jps命令直接羅列出了當前系統中存在的java程序,這裡第一個是jps命令自己的java程序,而另外一個是我啟動的nosql監控工具程序。通過這種方法查詢到java程式的程序ID後,可以進一步通過:

top -p 3618 // 這裡的3618就是上面查詢到的java程式的程序ID 在這裡插入圖片描述

通過此方法可以準確的檢視指定java程序的CPU/記憶體使用情況。

除此之外,vmstat命令也可以檢視系統CPU/記憶體、swap、io等情況: 在這裡插入圖片描述 上面的命令每隔1秒取樣一次,一共取樣四次。CPU佔用率很高,上下文切換頻繁,說明系統有執行緒正在頻繁切換,這可能是你的程式開啟了大量的執行緒存在資源競爭的情況。另外swap也是值得關注的指標,如果swpd過高則可能系統能使用的實體記憶體不足,不得不使用交換區記憶體,還有一個例外就是某些程式優先使用swap,導致swap飆升,而實體記憶體還有很多空餘,這些情況是需要注意的。

檢視系統指標,還有一個第三方工具:pidstat,這個工具還是很好用的,需要先安裝:

yum install sysstat

該命令監控程序id為3618的CPU狀態,每隔1秒取樣一次,一共取樣四次。“%CPU”表示CPU使用情況,“CPU”則表示正在使用哪個核的CPU,這裡為0表示正在使用第一個核。如果還要顯示執行緒ID,則可以使用:

pidstat -p 3618 -u -t 1 4 如果要監控磁碟讀寫情況,這可以使用: 在這裡插入圖片描述 pidstat還有其他的引數,可以通過pidstat --help獲取,再次不再贅述。

下面再介紹幾個JDK自帶有用的工具:jps、jstat、jmap、jstack。

jps:上面我們已經使用過了,他可以羅列出目前再伺服器上執行的java程式及程序ID;

jstat:用於輸出java程式記憶體使用情況,包括新生代、老年代、元資料區容量、垃圾回收情況。 圖片描述

上述命令輸出程序ID為3618的記憶體使用情況(每2000毫秒輸出一次,一共輸出20次)

S0:倖存1區當前使用比例 S1:倖存2區當前使用比例 E:伊甸園區使用比例 O:老年代使用比例 M:元資料區使用比例 CCS:壓縮使用比例 YGC:年輕代垃圾回收次數 FGC:老年代垃圾回收次數 FGCT:老年代垃圾回收消耗時間 GCT:垃圾回收消耗總時間 jmap:用於輸出java程式中記憶體物件的情況,包括有哪些物件,物件的數量。

jmap -histo 3618 上述命令打印出程序ID為3618的記憶體情況。但我們常用的方式是將指定程序的記憶體heap輸出到外部檔案,再由專門的heap分析工具進行分析,例如mat(Memory Analysis Tool),所以我們常用的命令是:

jmap -dump:live,format=b,file=heap.hprof 3618 將heap.hprof傳輸出來到window電腦上使用mat工具分析: 在這裡插入圖片描述

jstack:使用者輸出java程式執行緒棧的情況,常用於定位因為某些執行緒問題造成的故障或效能問題。

jstack 3618 > jstack.out 上述命令將程序ID為3618的棧資訊輸出到外部檔案,便於傳輸到windows電腦上進行分析。

Windows環境下的監控工具

Windows環境下的監控工具也有很多,但是本文主要推薦jvisualvm.exe、MemoryAnalyzer.exe,有了他們其他工具幾乎不需要了。

jvisualvm.exe在JDK安裝目錄下的bin目錄下面,雙擊即可開啟。 圖片描述

雙擊左側你需要監控的java程式即可對它進行監控,這個工具包括對CPU、記憶體、執行緒、類都做了監控,功能非常強大,上文中介紹的所有功能,其他在這個工具上都已經有了。當然怎麼用、如何分析它需要花時間去一點點積累。

MemoryAnalyzer.exe:上文我們已經提到,常用於分析記憶體堆使用情況,也是非常強大的工具。詳細使用方法,這裡就不再贅述,可以下載下來嘗試一下。

上述介紹了基於Linux、Windows環境的監控工具,有了這些工具我們就要利用他們做對應的事情,下面將通過一個簡單的案例,說明如何使用他們。

案例分析

首先通過上述的介紹,我們對故障排查流程應該有了一個印象,這裡先梳理出來:

案例:

一個java應用啟動以後,使用人員發現應用不可用,針對該現象我們做以下分析排查:

1、首先檢視伺服器上的應用狀態。使用jps命令查詢當前在執行中的java程序:

這裡程序ID為6400的java應用就是我們剛啟用的,說明應用並沒有掛掉,還在執行中。

2、通過程序ID查詢所佔用的CPU、記憶體以及當前負載情況,top -p 6400。 圖片描述

從以上結果看出該應用並沒有引起系統負載過高,CPU、記憶體也沒有出現異常情況。

3、通過上述結果我們推測因為記憶體原因引起的故障可效能較小,所以我們優先排查執行緒棧,使用jstack命令,匯出執行緒棧。

jstack 6400 > stack.out

我們將該檔案傳輸出來便於檢視。 在這裡插入圖片描述 檢視執行緒棧可以看出,主執行緒處於執行狀態,而子執行緒ThreadA、ThreadB、ThreadC、ThreadD一邊在等待一個鎖,同時又持有另外一個鎖,其實看到這裡我們基本推斷該應用程式存在死鎖,因此造成執行緒等待,應用不可用。通過以上棧的資訊,我們就可以到程式程式碼中詳細檢視程式碼了,並且修改bug解決此問題。

死鎖原理補充:

圖片描述

如圖所示,造成死鎖的原因是執行緒之間存在相互制約的情況,而任一執行緒都無法繼續執行。

小結

本文介紹了Linux、Windows環境下常用的監控工具,最後通過一個案例簡單說明故障排查的流程,怎麼使用監控工具找出應用故障的原因。