來源公眾號ytao ,
作者ytao
前言
Arthas 是Alibaba開源的Java診斷工具。在線排查問題,無需重啟;動態跟蹤Java代碼;實時監控JVM狀態。對分秒必爭的線上異常, Arthas可幫助我們快速診斷相關問題。
下載安裝
下載 Arthas的 arthas-boot.jar
wget https://alibaba.github.io/arthas/arthas-boot.jar
下載 arthas之後,先來了解幫助信息,可以通過 java-jar arthas-boot.jar-h命令查看,這裡給出了一些例子和參數說明
啟動
啟動 arthas之前,先啟動一個 springboot的應用。該 demo在地址https://github.com/yangtao9502/ytao-springboot-demo
java -jar ytao-springboot-demo.jar
啟動 arthas-boot.jar命令
java -jar arthas-boot.jar
這裡注意需要啟動 demo和 arthas使用同一權限用戶,否則使用attach機制獲取不到進程信息(這裡剛使用時沒注意,遇到過這個問題)。例:root用戶啟動 demo, u1用戶啟動 arthas時,列印信息 Cannotfind java process.Trytopass
查看源碼,在獲取進程之後,添加日誌輸出。結果為空,返回 -1,判斷結果小於 0時,直接退出。
啟動類 Bootstrap#main的代碼
進程工具類 ProcessUtils#select的代碼
通過上面也分析到,我們啟動 arthas之前,必須要先啟動我們的目標進程,否則 arthas可能無法啟動。
使用 root用戶啟動成功介面
選擇java進程,這裡我們的 ytao-springboot-demo是 1,選擇後會有連接信息
dashboard 數據面板
使用 dashboard命令,可以查看線程,內存,GC,以及Runtime信息
jad 反編譯
有時我們會遇到線上代碼運行結果不是我們期望的結果,有種情況就是線上代碼不是我們想要的版本,但是要查看的話,需要下載後再進行反編譯。這時 arthas的 jad可以幫助我們線上進行即時反編譯,確認代碼是否符合我們的版本。
jad com.ytao.service.UserServiceImpl
watch 函數執行信息
使用 watch命令可以查看函數的執行信息。watch的參數列表(來自官網)
當我們遇到線上數據 bug時,我們一般處理的手段就是開發環境模擬線上數據,從生產日誌中查找線索,再或者遠程 debug。以上不管哪種排查手段,相對都是比較麻煩。這時Arthas的 watch可以幫助我們查看實時的代碼執行情況。使用觀察表達式可以查看函數的 參數, 返回值, 異常信息。觀察表達式主要由 OGNL表達式組成,所以可以編寫 OGNL表達式來執行。
觀察表達式的變量
查看一個函數的入參和返回值
watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}"
列印信息 isEmpty=false;size=1可以看到參數為非空,參數數量為一個。查看具體入參信息
watch com.ytao.service.UserServiceImpl getUser "{params[0],returnObj}"
查看異常信息
watch com.ytao.service.UserServiceImpl getUser "throwExp"
當我們傳入一個參數為 -1時,列印出我們定義的非法參數異常
watch除了觀察表達式外,還能使用 條件表達式,以及 觀察事件點。注意使用觀察事件點時,有些觀察表達式的變量不一定存在,比如使用 -b時,返回值和異常信息都為空。
有時我們排查某個函數,不能馬上獲取到函數的信息, arthas給提供的 後台異步任務可以幫助我們記錄日誌。使用方式和Linux的類似。
watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}" > /log/w.log &
查看異步保存的日誌
tt 定位異常調用
上面所介紹的 watch可以排查函數的調用情況,比較適用在已知當次調用可能存在的情況後,查看信息。如果一個函數調用n次後,有幾次為執行異常,我們要去找出這些異常的調用,在 watch中排查就不怎麼方便了。使用 tt命令可以較方便查看異常的調用及信息。對 com.ytao.service.UserServiceImpl#getUser的函數查看, -t是每次調用該函數都會記錄
tt -t com.ytao.service.UserServiceImpl getUser
記錄信息
查看所有記錄
tt -l
查看指定函數記錄
tt -s 'method.name=="getUser"'
輸出信息說明
從上面參數中我們看到 1003調用是以拋異常的形式結束,因為 tt會記錄每次調用的信息,所以我們可以查看 1003的詳細信息
tt -i 1003
trace 查看調用鏈路
我們常會遇到調用某個api時rt過長,我們就要找出調用鏈上的某個或幾個函數進行優化,我們通常定位幾個可能的錨點,列印各個錨點間的rt。或者從日誌中找出日誌列印的時間點計算出時間差,不管使用哪種方法都比較繁瑣。當使用 arthas的 trace命令可以輕鬆的完成我們的需求。trace參數說明
使用 trace輸出 com.ytao.controller.UserController#getUser的信息
trace com.ytao.service.UserServiceImpl getUser
輸出結果
在實際使用使用排查過程中,為了減少無用信息的輸出,我們一般會使用 #cost過濾耗時不長和jdk自帶的函數,可以忽略的調用,減少信息的輸出。例如:過濾掉小於 1ms的調用
trace com.ytao.service.UserServiceImpl getUser '#cost > 1'
redefine 實現熱部署
當我們查找出bug,想要快速上線拯救蒼生的時候, Arthas為我們準備了 redefine命令來實現熱更新。儘管現在都在倡導 jad/ mc/ redefine熱更一條龍,但是線上代碼建議本地編譯好後再進行替換,避免手誤操作。首先先在 UserServiceImpl中添加一行代碼
獲取 classLoaderHash,通過 sc命令獲取類的信息
sc -d *UserServiceImpl
執行 redefine修改的類
redefine -c 1d56ce6a /usr/local/jar/UserServiceImpl.class
通過列印的信息驗證是否更新 UserServiceImpl類
Arthas的使用,除了上文中所講解到的,還有一些其他的診斷功能,這只是我個人使用的方法。但是使用該類工具一定要有套組合拳,對排查問題過程中,遇到問題有對應的排查手段,並非盲目排查。