Java 診斷工具 Arthas 教程學習筆記


Java 診斷利器 Arthas,是阿里的一款開源工具。Github-alibaba/arthas 上可以看到它的介紹。了解它,主要是最近對分析 Java 錯誤堆棧比較感興趣,機緣巧合看到了它。

本文記錄的內容,就是基於它官網的文檔摘抄的,涉及的截圖可能由於篇幅有限,不是很完整,建議按照官方文檔,實操一遍。

基礎教程

啟動 arthas-boot

wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar --target-ip 0.0.0.0

默認情況下, arthas server 偵聽的是 127.0.0.1 這個IP,如果希望遠程可以訪問,可以使用--target-ip 的參數

arthas-bootArthas 的啟動程序,它啟動后,會列出所有的 Java 進程,輸入需要診斷的目標進程序號即可。

Arthas支持通過 Web Socket來連接。

當在本地啟動時,可以訪問 http://127.0.0.1:8563/ ,通過瀏覽器來使用 Arthas。

輸入 help 可以看到常用的幫助命令:

arthas-boot.jar 支持很多參數,可以執行 java -jar arthas-boot.jar -h 查看

dashboard

  • dashboard 命令可以查看系統的實時數據面板。
  • qctrl+c 可以退出數據面展示。

數據說明:

  • ID: Java級別的線程ID,注意這個ID不能跟jstack中的nativeID一一對應
  • NAME: 線程名
  • GROUP: 線程組名
  • PRIORITY: 線程優先級, 1~10之間的數字,越大表示優先級越高
  • STATE: 線程的狀態
  • CPU%: 線程消耗的cpu占比,采樣100ms,將所有線程在這100ms內的cpu使用量求和,再算出每個線程的cpu使用占比。
  • TIME: 線程運行總時間,數據格式為分:秒
  • INTERRUPTED: 線程當前的中斷位狀態
  • DAEMON: 是否是daemon線程

thread

thread 1 打印線程 ID 1 的棧

Arthas 支持管道命令,可以利用 thread 1|grep 'main(' 查找 main class

查看 CPU 使用率 top n 的線程的棧,當前最忙的前 n 個線程:

thread -n 3

查看 5 秒內的 CPU 使用率 top n 的線程棧:

thread -n 3 -i 5000

-i 指定 CPU 占比統計的采樣間隔,單位為毫秒

查看線程是否有阻塞:

thread -b

有時候我們發現應用卡住了, 通常是由於某個線程拿住了某個鎖, 並且其他線程都在等待這把鎖造成的。 為了排查這類問題,此時使用 -b 參數,找到罪魁禍首。

注意, 目前只支持找出synchronized關鍵字阻塞住的線程, 如果是java.util.concurrent.Lock, 目前還不支持

sc -- 查找 JVM 加載類

Search-Class 的簡寫,這個命令能搜索出所有已經加載到 JVM 中的 Class 信息,sc -d *MathGame

如果搜索的是接口,還會搜索所有的實現類。比如查看所有的 Filter 實現類:

sc javax.servlet.Filter

-d 參數可以打印出類加載的具體信息,方便定位類加載問題

sc 支持通配符,比如搜索所有的 StringUtils

sc *StringUtils

打印類的 Field 信息:

sc -d -f demo.MathGame

sm -- 查看已加載類的方法信息

Search-Method 的簡寫,這個命令能搜索出所有已經加載了 Class 信息的方法信息。

sm 命令只能看到由當前類所聲明 (declaring) 的方法,父類則無法看到

查看 String 類的全部方法:

sm java.lang.String

查看具體方法的信息:

sm java.lang.String toString

通過 -d 參數可以打印函數的具體屬性,展示每個方法的詳細信息():

sm -d java.math.RoundingMode

jad

通過 jad 命令反編譯代碼:

jad demo.MatthGame

Watch

watch 命令可以查看函數的:

  • 參數
  • 返回值
  • 異常信息
watch demo.MathGame primeFactors returnObj

watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2
  1. 第一個參數是類名,支持通配
  2. 第二個參數是函數名,支持通配
  3. 第三個參數是定義返回值
  4. -x 2 是為了將結果展開

返回值表達式實際是一個 ognl 表示,支持一些內置對象:

  • loader
  • clazz
  • method
  • target
  • params
  • returnObj
  • throwExp
  • isBefore
  • isThrow
  • isReturn

watch命令支持按請求耗時進行過濾:

watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'

Arthas在 watch/trace 等命令時,實際上是修改了應用的字節碼,插入增強的代碼。顯式執行 reset 命令,可以清除掉這些增強代碼

退出 Arthas

exitquit 可以退出 Arthas

退出 Arthas 之后,還可以再次使用 java -jar arthas-boot.jar 來鏈接

exit/quit 命令只是退出當前 session,arthas server 還在目標進程中運行,shutdown 命令才能完全退出 Arthas。

進階

啟動 Spring Boot Demo

wget https://github.com/hengyunabc/katacoda-scenarios/raw/master/demo-arthas-spring-boot.jar
java -jar demo-arthas-spring-boot.jar

啟動 arthas-boot

wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar --target-ip 0.0.0.0

就像基礎教程說過的,選擇目標進程

查看 JVM 信息

sysprop

查看當前 JVM 的系統屬性(System Property)

  • sysprop 打印所有 System Properties
  • 指定單個 key:sysprop java.version
  • 通過 grep 過濾:sysprop|grep user
  • 設置新的value: sysprop testKey testValue

sysenv

sysenv 命令查看當前 JVM 的環境屬性(System Environment Variables)

也是支持查看單個環境變量值的:

sysenv USER

jvm

jvm 命令可以打印 JVM 的各種信息

Thread 相關:

  • COUNT: JVM 當前活躍的線程數
  • DAEMON-COUNT: JVM 當前活躍的守護線程數
  • PEAK-COUNT: 從J VM 啟動開始曾經活着的最大線程數
  • STARTED-COUNT: 從 JVM 啟動開始總共啟動過的線程次數
  • DEADLOCK-COUNT: JVM 當前死鎖的線程數

文件描述符相關:

  • MAX-FILE-DESCRIPTOR-COUNT:JVM 進程最大可以打開的文件描述符數
  • OPEN-FILE-DESCRIPTOR-COUNT:JVM 當前打開的文件描述符數

ognl

獲取靜態類的靜態字段:

ognl '@demo.MathGame@random'

具體,查看執行ognl表達式

trace

方法內部調用路徑,並輸出方法路徑上的每個節點上耗時

trace 命令能主動搜索 class-pattern/method-pattern 對應的方法調用路徑,渲染和統計整個調用鏈路上的所有性能開銷和追蹤調用鏈路

參數名稱 參數說明
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
condition-express 條件表達式
[E] 開啟正則表達式匹配,默認為通配符匹配
[n:] 命令執行次數
#cost 方法執行耗時

很多時候我們只想看到某個方法的 rt 大於某個時間之后的 trace 結果,現在 Arthas 可以按照方法執行的耗時來進行過濾了,例如 trace *StringUtils isBlank '#cost>100' 表示當執行時間超過 100ms 的時候,才會輸出 trace 的結果。

watch/stack/trace 這個三個命令都支持 #cost

trace 函數:

$ trace demo.MathGame run
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 42 ms.
`---ts=2018-12-04 00:44:17;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[10.611029ms] demo.MathGame:run()
        +---[0.05638ms] java.util.Random:nextInt()
        +---[10.036885ms] demo.MathGame:primeFactors()
        `---[0.170316ms] demo.MathGame:print()

過濾掉 jdk 的函數:

$ trace -j  demo.MathGame run
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 31 ms.
`---ts=2018-12-04 01:09:14;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[5.190646ms] demo.MathGame:run()
        +---[4.465779ms] demo.MathGame:primeFactors()
        `---[0.375324ms] demo.MathGame:print()
  • -j: jdkMethodSkip, skip jdk method trace

trace 在執行的過程中本身是會有一定的性能開銷,在統計的報告中並未像 JProfiler 一樣預先減去其自身的統計開銷

stack

輸出當前方法被調用的調用路徑

很多時候我們都知道一個方法被執行,但這個方法被執行的路徑非常多,或者你根本就不知道這個方法是從那里被執行了,此時你需要的是 stack 命令。

參數名稱 參數說明
class-pattern 類名表達式匹配
method-pattern 方法名表達式匹配
condition-express 條件表達式
[E] 開啟正則表達式匹配,默認為通配符匹配
[n:] 執行次數限制

據執行時間來過濾:

$ stack demo.MathGame primeFactors '#cost>5'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 35 ms.
ts=2018-12-04 01:35:58;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    @demo.MathGame.run()
        at demo.MathGame.main(MathGame.java:16)

Arthas 使用技巧

  • 每個命令,都可以加上 -h 來查看對應的幫助信息,例如:sc -h
  • Tab 自動補全,例如:sysprop java. 按下 Tab 鍵,會補全對應的 key
  • 支持常見的命令行快捷鍵,比如 ctrl+a/e,更多輸入 keymap 查看
  • 歷史命令補全,輸入一半時,按下Up/↑Down/↓ 來匹配,例如 sysprop ja 之后,按下 會幫你自動補全
  • 管道命令支持,例如 sysprop | wc -l

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM