大家好,我是Yuan,今天給大家介紹一款調(diào)優(yōu)神器 -- 阿里巴巴Arthas,可以幫助你的應(yīng)用釋放潛力。
1. 介紹
阿里巴巴 Arthas 是一個(gè)診斷工具,可以用于監(jiān)視、分析和解決 Java 應(yīng)用程序的問題。使用 Arthas 的一個(gè)主要優(yōu)點(diǎn)是,我們不需要修改代碼,甚至不需要重新啟動(dòng)我們想要監(jiān)視的 Java 服務(wù)。
在本教程中,我們將首先安裝 Arthas,在此之后,通過一個(gè)簡(jiǎn)單的案例來(lái)演示 Arthas 的一些關(guān)鍵特性。
最后,由于 Arthas 是用 Java 編寫的,因此它是跨平臺(tái)的,可以在 Linux、macOS 和 Windows 上運(yùn)行。
2. 下載和入門
首先,我們可以通過直接下載鏈接或使用curl來(lái)下載 Arthas 庫(kù):
curl-Ohttps://alibaba.github.io/arthas/arthas-boot.jar
現(xiàn)在,讓我們通過運(yùn)行帶有-h(幫助)選項(xiàng)的 Arthas 來(lái)測(cè)試它是否工作:
java-jararthas-boot.jar-h
如果成功,我們應(yīng)該看到顯示所有命令的幫助指南:
3. 案例分析
在本教程中,我們將使用一個(gè)非常簡(jiǎn)單的應(yīng)用程序,基于利用遞歸實(shí)現(xiàn)的斐波那契數(shù)列的相對(duì)低效的實(shí)現(xiàn)方式:
publicclassFibonacciGenerator{
publicstaticvoidmain(String[]args){
System.out.println("按任意鍵繼續(xù)");
System.in.read();
for(inti=0;i100;i++){
longresult=fibonacci(i);
System.out.println(format("fib(%d):%d",i,result));
}
}
publicstaticlongfibonacci(intn){
if(n==0||n==1){
return1L;
}else{
returnfibonacci(n-1)+fibonacci(n-2);
}
}
}
這個(gè)示例的最有趣的部分是遵循斐波那契數(shù)列的數(shù)學(xué)定義的 fibonacci 方法。
在 main 方法中,我們使用一個(gè)循環(huán)和相對(duì)較大的數(shù)字,以便讓計(jì)算機(jī)進(jìn)行較長(zhǎng)時(shí)間的計(jì)算。這當(dāng)然正是我們想要的,以便演示 Arthas。
4. 啟動(dòng) Arthas
現(xiàn)在讓我們?cè)囋?Arthas!我們需要做的第一件事是運(yùn)行我們的小型斐波那契應(yīng)用程序。我們可以使用我們喜歡的 IDE 或直接在終端中運(yùn)行它。它會(huì)要求按下一個(gè)鍵才能啟動(dòng)。我們將在將進(jìn)程附加到 Arthas 之后按下任意鍵。
現(xiàn)在,讓我們運(yùn)行 Arthas 可執(zhí)行文件:
java-jararthas-boot.jar
Arthas 提示選擇要附加到的進(jìn)程:
[INFO]arthas-bootversion:3.1.7
[INFO]Foundexistingjavaprocess,pleasechooseoneandhitRETURN.
*[1]:25500com.baeldung.arthas.FibonacciGenerator
...
讓我們選擇名稱為 com.baeldung.arthas.FibonacciGenerator 的進(jìn)程。在此示例中,只需在列表中輸入數(shù)字‘1’并按 Enter 即可。
Arthas 現(xiàn)在會(huì)附加到該進(jìn)程并啟動(dòng):
[INFO]Trytoattachprocess25500
[INFO]Attachprocess25500success.
...
一旦 Arthas 啟動(dòng),我們就有一個(gè)提示符,可以發(fā)出不同的命令。
我們可以使用 help 命令獲取有關(guān)可用選項(xiàng)的更多信息。為了方便使用 Arthas,我們還可以使用 tab 鍵來(lái)自動(dòng)完成其命令。
在將 Arthas 附加到進(jìn)程后,我們現(xiàn)在可以按下一個(gè)鍵,程序?qū)㈤_始打印斐波那契數(shù)。
5. 儀表盤
一旦 Arthas 啟動(dòng),我們可以使用儀表盤。在這種情況下,我們通過輸入 "dashboard" 命令來(lái)使用儀表盤。現(xiàn)在,我們可以看到一個(gè)詳細(xì)的屏幕,其中包含多個(gè)面板和關(guān)于我們的 Java 進(jìn)程的許多信息:
讓我們更詳細(xì)地看一下其中的一些內(nèi)容:
- 頂部區(qū)域?qū)iT顯示當(dāng)前正在運(yùn)行的線程
- 一個(gè)重要的列是每個(gè)線程的 CPU 使用情況
- 第三部分顯示每個(gè)線程的 CPU 時(shí)間
- 另一個(gè)有趣的面板是內(nèi)存分析。不同的內(nèi)存區(qū)域以及它們的統(tǒng)計(jì)信息都列在其中。在右側(cè),我們有垃圾收集器的信息
- 最后,在第五部分,我們有關(guān)于主機(jī)平臺(tái)和 JVM 的信息
我們可以通過按下 "q" 鍵退出儀表盤。
我們應(yīng)該記住,即使退出,Arthas 仍會(huì)附加到我們的進(jìn)程上。因此,為了正確地從我們的進(jìn)程中斷開它的連接,我們需要運(yùn)行 "stop" 命令。
6. 分析堆棧跟蹤
在儀表盤中,我們看到我們的主進(jìn)程占用了幾乎 100% 的 CPU。該進(jìn)程的 ID 是 1,在第一列中可以看到。
現(xiàn)在我們已經(jīng)退出了儀表盤,我們可以通過運(yùn)行 "thread" 命令來(lái)更詳細(xì)地分析該進(jìn)程:
thread1
作為參數(shù)傳遞的數(shù)字是線程 ID。Arthas 打印出一個(gè)堆棧跟蹤信息,其中充斥著對(duì) fibonacci 方法的調(diào)用。
如果堆棧跟蹤信息很長(zhǎng)而且難以閱讀,可以使用 "thread" 命令結(jié)合 "grep" 命令來(lái)過濾:
thread1|grep'main('
這將只打印與 "grep" 命令匹配的行:
[arthas@25500]$thread1|grep'main('
atcom.baeldung.arthas.FibonacciGenerator.main(FibonacciGenerator.java:10)
7. 反編譯Java類
假設(shè)我們正在分析一個(gè)我們對(duì)其中了解甚少或一無(wú)所知的Java應(yīng)用程序,突然發(fā)現(xiàn)堆棧中充斥著以下類型的重復(fù)調(diào)用:
[arthas@59816]$thread1
"main"Id=1RUNNABLE
atapp//com.baeldung.arthas.FibonacciGenerator.fibonacci(FibonacciGenerator.java:18)
atapp//com.baeldung.arthas.FibonacciGenerator.fibonacci(FibonacciGenerator.java:18)
...
由于我們運(yùn)行了Arthas,我們可以反編譯一個(gè)類來(lái)查看其內(nèi)容。為了實(shí)現(xiàn)這一點(diǎn),我們可以使用jad命令,將限定類名作為參數(shù)傳遞:
jadcom.baeldung.arthas.FibonacciGenerator
類加載器:
+-jdk.internal.loader.ClassLoaders$AppClassLoader@799f7e29
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@60f1dd34
位置:
/home/amoreno/work/baeldung/tutorials/libraries-3/target/
/*
*反編譯使用CFR。
*/
packagecom.baeldung.arthas;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.PrintStream;
publicclassFibonacciGenerator{
publicstaticvoidmain(String[]arrstring)throwsIOException{
輸出是反編譯的Java類和一些有用的元數(shù)據(jù),如類的位置。這是一個(gè)非常有用和強(qiáng)大的功能。
8. 搜索類和搜索方法
搜索類命令在搜索JVM中加載的類時(shí)非常方便。我們可以使用它通過輸入sc并將模式作為參數(shù)傳遞來(lái)使用,帶或不帶通配符:
[arthas@70099]$sc*Fibonacci*
com.baeldung.arthas.FibonacciGenerator
Affect(row-cnt:1)costin5ms.
一旦我們獲得了類的限定名稱,我們可以使用兩個(gè)附加標(biāo)志來(lái)查找更多信息:
- -d顯示類的詳細(xì)信息
- -f顯示類的字段
然而,類的字段必須與詳細(xì)信息一起查詢:
[arthas@70099]$sc-dfcom.baeldung.arthas.FibonacciGenerator
class-infocom.baeldung.arthas.FibonacciGenerator
...
同樣,我們可以使用sm(搜索方法)命令來(lái)查找類中加載的方法。在這種情況下,對(duì)于我們的類com.baeldung.arthas.FibonacciGenerator,我們可以運(yùn)行:
[arthas@70099]$smcom.baeldung.arthas.FibonacciGenerator
com.baeldung.arthas.FibonacciGenerator()V
com.baeldung.arthas.FibonacciGeneratormain([Ljava/lang/String;)V
com.baeldung.arthas.FibonacciGeneratorfibonacci(I)J
Affect(row-cnt:3)costin4ms.
我們可以使用-d標(biāo)志來(lái)檢索方法的詳細(xì)信息。最后,我們可以傳遞方法的名稱作為可選參數(shù),以縮小返回方法的數(shù)量:
sm-dcom.baeldung.arthas.FibonacciGeneratorfibonacci
declaring-classcom.baeldung.arthas.FibonacciGenerator
method-namefibonacci
modifierpublic,static
annotation
parametersint
returnlong
exceptions
classLoaderHash799f7e29
9. 監(jiān)視方法調(diào)用
我們可以使用Arthas來(lái)監(jiān)視方法,這在調(diào)試應(yīng)用程序的性能問題時(shí)非常方便。為此,我們可以使用monitor命令。
monitor命令需要一個(gè)-c <秒數(shù)>標(biāo)志和兩個(gè)參數(shù) - 限定類名和方法名。
對(duì)于我們的案例研究,讓我們來(lái)調(diào)用monitor:
monitor-c10com.baeldung.arthas.FibonacciGeneratorfibonacci
正如我們所預(yù)期的,Arthas將每10秒打印有關(guān)fibonacci方法的指標(biāo):
Affect(class-cnt:1,method-cnt:1)costin47ms.
timestampclassmethodtotalsuccessfailavg-rt(ms)fail-rate
-----------------------------------------------------------------------------------------------------------------------------
2020-03-071126com.baeldung.arthas.FibonacciGeneratorfibonacci52895752895700.070.00%
...
對(duì)于那些最終失敗的調(diào)用,我們也有指標(biāo) - 這對(duì)于調(diào)試很有用。
10. 監(jiān)控方法參數(shù)
如果我們需要調(diào)試方法的參數(shù),我們可以使用watch命令。但是,語(yǔ)法會(huì)稍微復(fù)雜一些:
watchcom.baeldung.arthas.FibonacciGeneratorfibonacci'{params[0],returnObj}''params[0]>10'-n10
讓我們?cè)敿?xì)看一下各個(gè)參數(shù):
- 第一個(gè)參數(shù)是類名
- 第二個(gè)參數(shù)是方法名
- 第三個(gè)參數(shù)是定義我們要查看的內(nèi)容的OGNL表達(dá)式 - 在這種情況下,它是第一個(gè)(也是唯一的)方法參數(shù)和返回值
- 第四個(gè)和最后一個(gè)可選參數(shù)是用于過濾我們要監(jiān)視的調(diào)用的布爾表達(dá)式
對(duì)于此示例,我們只想在參數(shù)大于10時(shí)監(jiān)視。最后,我們添加一個(gè)標(biāo)志來(lái)限制結(jié)果為10個(gè):
watchcom.baeldung.arthas.FibonacciGeneratorfibonacci'{params[0],returnObj}''params[0]>10'-n10
按Q或Ctrl+C中斷。
Affect(class-cnt:1,method-cnt:1)costin19ms.
ts=2020-02-172108;[cost=30.165211ms]result=@ArrayList[
@Integer[11],
@Long[144],
]
ts=2020-02-172108;[cost=50.405506ms]result=@ArrayList[
@Integer[12],
@Long[233],
]
...
在這里,我們可以看到帶有CPU時(shí)間和輸入/返回值的調(diào)用示例。
11. 分析器
對(duì)于那些對(duì)應(yīng)用程序性能感興趣的人來(lái)說,通過分析器命令提供了一種非常直觀的能力。分析器將評(píng)估我們的進(jìn)程正在使用的CPU的性能。
讓我們通過運(yùn)行profiler start來(lái)啟動(dòng)分析器。這是一個(gè)非阻塞的任務(wù),意味著在分析器工作時(shí)我們可以繼續(xù)使用Arthas。
隨時(shí)可以通過運(yùn)行profiler getSamples來(lái)詢問分析器有多少個(gè)樣本。
現(xiàn)在讓我們使用profiler stop來(lái)停止分析器。此時(shí),一個(gè)FlameGraph圖像將被保存。在這個(gè)具體的案例中,我們有一個(gè)以斐波那契線程為主導(dǎo)的圖表:
注意,當(dāng)我們想要檢測(cè)我們的CPU時(shí)間花在哪里時(shí),這個(gè)圖表特別有用。
12. 總結(jié)
在本教程中,我們探索了Arthas的一些最強(qiáng)大和有用的功能。
正如我們所見,Arthas有許多命令可以幫助我們?cè)\斷各種問題。當(dāng)我們無(wú)法訪問正在審查的應(yīng)用程序的代碼,或者我們想快速診斷在服務(wù)器上運(yùn)行的有問題的應(yīng)用程序時(shí),它也可以特別有幫助。
-
JAVA
+關(guān)注
關(guān)注
19文章
2974瀏覽量
105135 -
阿里巴巴
+關(guān)注
關(guān)注
7文章
1619瀏覽量
47520 -
應(yīng)用程序
+關(guān)注
關(guān)注
38文章
3292瀏覽量
57911
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論