天天看點

arthas 阿爾薩斯 Java診斷工具

下載下傳和安裝

curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar           

使用as.sh

curl -L https://alibaba.github.io/arthas/install.sh | sh           

直接在shell下面執行./as.sh,就會進入互動界面。

也可以執行./as.sh -h來擷取更多參數資訊。

常用的指令

基本指令

  • help——檢視指令幫助資訊
  • cat——列印檔案内容,和linux裡的cat指令類似
  • pwd——傳回目前的工作目錄,和linux指令類似
  • cls——清空目前螢幕區域
  • session——檢視目前會話的資訊
  • reset——重置增強類,将被 Arthas 增強過的類全部還原,Arthas 服務端關閉時會重置所有增強過的類
  • version——輸出目前目标 Java 程序所加載的 Arthas 版本号
  • history——列印指令曆史
  • quit——退出目前 Arthas 用戶端,其他 Arthas 用戶端不受影響
  • shutdown——關閉 Arthas 服務端,所有 Arthas 用戶端全部退出

檢視系統整體情況

  • dashboard——目前系統的實時資料面闆
  • thread——檢視目前 JVM 的線程堆棧資訊
  • jvm——檢視目前 JVM 的資訊
  • sysprop——檢視和修改JVM的系統屬性
  • sysenv——檢視JVM的環境變量
  • getstatic——檢視類的靜态屬性

類相關指令

  • sc——檢視JVM已加載的類資訊
  • sm——檢視已加載類的方法資訊
  • jad——反編譯指定已加載類的源碼
  • mc——記憶體編繹器,記憶體編繹.java檔案為.class檔案
  • redefine——加載外部的檔案,redefine到JVM裡
  • dump——dump 已加載類的 byte code 到特定目錄
  • classloader——檢視classloader的繼承樹,urls,類加載資訊,使用classloader去getResource

監控相關

  • monitor——方法執行監控
  • watch——方法執行資料觀測
  • trace——方法内部調用路徑,并輸出方法路徑上的每個節點上耗時
  • stack——輸出目前方法被調用的調用路徑
  • tt——方法執行資料的時空隧道,記錄下指定方法每次調用的入參和傳回資訊,并能對這些不同的時間下調用進行觀測

問題

  • 初次使用時的一些問題
[ERROR] Target process 9298 is not the process using port 3658, you will connect to an unexpected process.
[ERROR] 1. Try to restart as.sh, select process 959, shutdown it first with running the 'stop' command.
[ERROR] 2. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1           
這個問題初用者必出,原因為 arthas 選擇一個應用進行診斷時弄了一個 session,可以使用 arthas-client ,web arthas client 進行登入,這個提示告訴你要先關閉以前的 arthas-boot ,或者重新選擇一個端口。

在 ~/.arthas/lib/3.1.7/arthas 下有一個 arthas-client.jar 使用 java -jar arthas-client.jar 可以進入上次的 session ,shutdown 後就可以選擇其它的程序進行診斷了,或者你可以繼續診斷目前應用

  • 反編譯失敗
Memory compiler error, exception message: Compilation Error
line: 9 , message: package org.springframework.stereotype does not exist ,
line: 11 , message: cannot find symbol
  symbol: class Service ,
, please check $HOME/logs/arthas/arthas.log for more details.
Affect(row-cnt:0) cost in 16 ms.           
  • mc指令有可能失敗。如果編譯失敗可以在本地編譯好.class檔案,再上傳到伺服器
  • 可以使用sc命名查找相應類的ClassLoader,擷取classLoaderHash。再用mc指令進行反編譯
# 擷取classLoaderHash
sc -d *SayService | grep classLoaderHash
# classLoaderHash   439f5b3d

# 使用classLoaderHash進行反編譯
mc -c 439f5b3d /tmp/SayService.java -d /tmp           

實戰操作

  • 使用monitor指令對類、方法的調用進行監控。
monitor -c 2 com.example.arthastest.service.SayService sayHello           
arthas 阿爾薩斯 Java診斷工具

從上圖的監控可以看出類SayService的sayHello方法耗時抖動比較大,需進一步排查

  • 使用trace指令對方法内部調用路徑,并輸出方法路徑上的每個節點上耗時統計
trace com.example.arthastest.service.SayService sayHello '#cost > 300'           
arthas 阿爾薩斯 Java診斷工具

從上圖的監控資料可以看到processName方法耗時多

  • 使用watch指令觀察到指定方法的調用情況。能觀察到的範圍為:傳回值、抛出異常、入參,通過編寫 OGNL 表達式進行對應變量的檢視。
watch com.example.arthastest.service.SayService processName "{params,returnObj}" -x 2  '#cost>300'           
arthas 阿爾薩斯 Java診斷工具

從上圖的監控可以看出傳入參數xiaoming時的耗時較多

  • 使用jad反編譯指定已加載類的源碼
jad --source-only com.example.arthastest.service.SayService

# 可以使用如下指令将生成後的源碼指定到檔案中
jad --source-only com.example.arthastest.service.SayService > /tmp/SayService.java           
arthas 阿爾薩斯 Java診斷工具

看到反編譯後的代碼,基本可以确認問題出在哪裡。

  • 使用sc指令擷取加載該方法的classLoaderHash
sc -d *SayService | grep classLoaderHash           
arthas 阿爾薩斯 Java診斷工具
  • 修改源碼後使用mc編譯.java檔案生成.class

    修改後的源碼如下圖

arthas 阿爾薩斯 Java診斷工具
mc -c 439f5b3d /tmp/SayService.java -d /tmp           
  • 使用redefine指令重新加載修改後的代碼
redefine -c 439f5b3d  /tmp/com/example/arthastest/service/SayService.class           

再次使用相同的參數通路該方法,會發現耗時明顯降低。

注意:redefine指令和jad/watch/trace/monitor/tt等指令會沖突。執行完redefine之後,如果再執行上面提到的指令,則會把redefine的位元組碼重置。 原因是jdk本身redefine和Retransform是不同的機制,同時使用兩種機制來更新位元組碼,隻有最後修改的會生效。redefine後使用jad再次檢視源碼會發現依舊是以前的,這是指令沖突導緻的,會使已生效redefine修改失效。

參考文檔