arthas中文直譯過來叫阿爾薩斯,是阿里巴巴開源的java應用診斷工具,在線排查問題,無需重啟服務,實時監(jiān)控jvm狀態(tài)。支持JDK6以上版本,支持Linux/Mac/Window操作系統(tǒng)。
采用命令行交換方式,tab鍵命令自動補全,而且兼容linux系統(tǒng)部分命令,如:grep,ctrl+i清屏,ctrl+a跳到行首,ctrl+c終止命令等
如果你還在使用jdk原生jstat、jmap等命令排查問題,那么,強烈建議你使用arthas。本文介紹arthas的下載安裝、啟動、常用命令、退出、卸載以及常見問題的調試步驟
arthas安裝分為快速安裝和全量安裝,快速安裝只下載arthas-boot.jar。全量安裝是下載一個壓縮包,壓縮包中包含arthas-boot.jar、測試demo和封裝好的啟動腳本等文件,一般我們使用快速安裝就可以了
快速安裝
linux系統(tǒng)中安裝可以用curl命令從阿里云官方網(wǎng)站下載
curl -O?https://arthas.aliyun.com/arthas-boot.jar
windows系統(tǒng)中安裝用瀏覽器打開如下地址會提示下載
https://arthas.aliyun.com/arthas-boot.jar
全量安裝
linux全量安裝需要先下載執(zhí)行腳本
curl -L?https://arthas.aliyun.com/install.sh?|?sh
下載完成后會在當前目錄生成as.sh腳本,執(zhí)行腳本 ./as.sh 后會自動下載全量安裝包,默認保存在~/.arthas/lib目錄下。修改as.sh腳本可以更改默認保存路徑
windows全量安裝只需要用瀏覽器打開下載地址就會提示下載
https://arthas.aliyun.com/download/latest_version?mirror=aliyun
全量安裝包的文件夾名稱為arthas,目錄結構如下
啟動
啟動之前需要明確要監(jiān)聽哪個java程序,并找到這個java程序的進程id。當前登錄用戶必須對要監(jiān)聽的進程有可操作權限,否則會報錯
linux中使用ps或jps命令可以找到java程序的進程id
ps -ef?|?grep?java?
jps?-mlv
windows中打開任務管理器可以找到對應程序的進程id
執(zhí)行命令啟動arthas
java -jar arthas-boot.jar
啟動后會提示選擇監(jiān)聽哪個進程id,輸入對應的序號即可。我要監(jiān)聽的進程id是19646,也就是序號2
輸入2之后敲回車,啟動成功如下圖
啟動時可以直接指定pid,就不用在啟動過程中再輸入序號了
java -jar arthas-boot.jar 19646
如果安裝時選擇了全量安裝,那么也可以通過腳本啟動,linux系統(tǒng)使用as.sh腳本,windows系統(tǒng)使用as.bat腳本
查看dashboard
dashboard命令可以查看cpu、線程狀態(tài),內存信息、GC情況和jdk版本等信息
圖中字段解讀
ID:?Java中的線程ID,注意這個ID不能跟jstack中的nativeID一一對應 NAME:?線程名稱 GROUP:?線程組名稱 PRIORITY:?線程優(yōu)先級,?1~10之間的數(shù)字,越大表示優(yōu)先級越高 STATE:?線程的狀態(tài) CPU%:?線程消耗的cpu占比,采樣間隔100ms,將所有線程在這100ms內的cpu使用量求和,再算出每個線程的cpu使用占比。 TIME:?線程運行總時間,格式為?分:秒 INTERRUPTED:?線程當前的中斷狀態(tài) DAEMON:?是否是守護線程
監(jiān)控頁面會實時刷新,默認每5000毫秒(5秒)刷新一次。可以通過 - i 參數(shù)指定刷新頻率,-n 參數(shù)指定刷新次數(shù)。這個統(tǒng)計會有一定的開銷,從截圖中也可以看到arthas的cpu占比較大,所以刷新頻率不要太高,建議5秒以上,刷新次數(shù)建議10次以內
//?每10秒刷新一次,3次后停止 dashboard?-i 10000 -n 3
查看線程
使用thread命令可以查看線程的狀態(tài),顯示的結果實際就是dashboard結果的第一欄
thread命令可以追加參數(shù)
id:可以查看指定線程id的堆棧信息?
-n value:找出最忙的value個線程,并打印堆棧信息?
-b:找出當前正在阻塞其他線程的線程?
-i value:指定采樣cpu占比的時間間隔,默認為100ms。
打印線程id=24的堆棧信息
打印當前最忙的3個線程的堆棧信息
打印正在阻塞其他線程的線程
指定統(tǒng)計線程cpu占比的時間間隔,單位:毫秒。因為統(tǒng)計cpu占比會有一定的資源消耗,所以時間間隔不要太小,建議100毫秒以上
thead?-i 200
反編譯
使用jad可以對代碼進行反編譯,反編譯過來的代碼可能會有語法錯誤,但不影響閱讀。比較貼心的是,反編譯過來的代碼語法高亮,方便閱讀
類名支持全路徑,同時也支持模糊匹配,下面兩個命令可以達到相同的效果
jad com.helianxiaowu.demo.ThreadBlock jad *ThreadBlock
也可以對類中的某一個方法進行反編譯,只需要在類名后面加上方法名即可
反編譯過來的代碼默認攜帶ClassLoader信息,使用 --source-only 選項可以去除ClassLoader信息
使用quit或exit會退出arthas操作界面,但arthas進程還在,這時當你想監(jiān)聽別的java進程時會報錯。因為arthas默認使用的是3658端口,所以這時會報錯3658端口被別的進程占用。
使用shutdown或stop可以結束arthas,結束后可以監(jiān)聽別的進程id
出現(xiàn)端口被占用報錯時,可以再次啟動進入剛才監(jiān)聽的進程或者使用telnet進入剛才監(jiān)聽的arthas進程界面,執(zhí)行shutdown或stop結束監(jiān)聽
telnet?localhost 3658
卸載
linu系統(tǒng)中執(zhí)行如下命令進行卸載
rm?-rf?~/.arthas/ rm?-rf?~/logs/arthas
window下需要進入C盤當前用戶的目錄,找到 .arthas目錄和logs/arthas目錄進行刪除
java程序中,頻繁GC、鏈接沒有釋放、線程數(shù)量過多導致頻繁的進行切換、線程被阻塞、死循環(huán)等原因是造成cpu飆升的主要原因。
通過arthas的dashboard命令可以看到GC的回收次數(shù)和時間,現(xiàn)在大部分程序都是使用spring進行對象管理,不會出現(xiàn)創(chuàng)建大量實例對象的情況。數(shù)據(jù)庫鏈接、IO、HTTP鏈接都使用的鏈接池,也很少出現(xiàn)鏈接沒有釋放的問題。所以,JVM頻繁進行GC操作,很有可能是內存設置不合理,可以使用如下參數(shù)指定內存
JAVA_OPTS="-server?-Xms256m?-Xmx512m?-XX:PermSize=64M?-XX:MaxPermSize=128m"
線程數(shù)量過多導致頻繁進行線程切換,基本可以斷定當前服務支撐不了現(xiàn)有的并發(fā)了,需要增加服務器資源或者增加負載
現(xiàn)在來模擬一個cpu飆升的問題排查過程
首先啟動測試程序,模擬cpu升高的情況
然后啟動arthas,選擇測試程序對應的進程進行監(jiān)控。輸入dashboard命令,可以看到id=10的這個線程占用cpu過高
打印id=10的線程堆棧信息,可以看到這個線程正在執(zhí)行high()方法
反編譯high方法,查看源碼,可以看到進行了死循環(huán),所以cpu會飆升
一個接口調用,好長時間才能收到響應,接口邏輯復雜,排查起來特別困難,不知從何下手?下面帶你一步步找到問題
找到調用耗時較長的接口,這里測試使用的是MethodDemo類中的slow()方法。
啟動測試程序,調用slow方法,可以看到該方法耗時足足10秒,確實很慢
在arthas監(jiān)控頁面輸入如下命令對這個方法進行耗時統(tǒng)計
trace *MethodDemo?slow
在統(tǒng)計結果中,能看到每個方法的調用時長
反編譯slow方法,發(fā)現(xiàn)代碼進行了sleep操作,所以耗時較長
trace命令是統(tǒng)計方法的內部調用路徑,并為每個調用路徑統(tǒng)計耗時。trace命令需要指定類名和方法名,支持模糊匹配
線程阻塞會導致并發(fā)量上不去、cpu占用過高,降低系統(tǒng)整體性能,嚴重時會導致系統(tǒng)崩潰
啟動測試程序,調用演示線程阻塞的方法
進入arthas監(jiān)控頁面,找到目前正在阻塞其他線程的線程,可以看到loop方法中正在鎖定一個字符串,阻塞了其他線程
反編譯loop方法,可以看到使用了synchronized進行了同步操作,阻塞了其他線程
由于篇幅有限,本文只講一些arthas常用操作,后期會再出一篇高級操作,包括webconsole遠程監(jiān)控服務器、ognl表達式、封裝docker鏡像等。
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!