1.Arthas是什么
Arthas是Alibaba開源的Java診斷工具
他主要解決以下問(wèn)題
1.這個(gè)類從哪個(gè) jar 包加載的泳唠?為什么會(huì)報(bào)各種類相關(guān)的 Exception?
2.我改的代碼為什么沒(méi)有執(zhí)行到辆毡?難道是我沒(méi) commit?分支搞錯(cuò)了皱坛?
3.遇到問(wèn)題無(wú)法在線上 debug报慕,難道只能通過(guò)加日志再重新發(fā)布嗎?
4.線上遇到某個(gè)用戶的數(shù)據(jù)處理有問(wèn)題蜻拨,但線上同樣無(wú)法 debug池充,線下無(wú)法重現(xiàn)!
5.是否有一個(gè)全局視角來(lái)查看系統(tǒng)的運(yùn)行狀況官觅?
6.有什么辦法可以監(jiān)控到JVM的實(shí)時(shí)運(yùn)行狀態(tài)纵菌?
7.怎么快速定位應(yīng)用的熱點(diǎn)阐污,生成火焰圖休涤?
8.怎樣直接從JVM內(nèi)查找某個(gè)類的實(shí)例?
更多細(xì)節(jié)請(qǐng)參考官網(wǎng):https://arthas.aliyun.com/doc/
2.下載安裝
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
啟動(dòng)后選擇第一個(gè)進(jìn)程進(jìn)入笛辟,這里輸入1選第一個(gè)進(jìn)程
也可以通過(guò)jps查詢到pid先功氨,然后直接綁定pid和port
java -jar arthas-boot.jar --http-port {port} {pid}
3.常用命令
3.1 dashboard
輸入dashboard,按回車/enter
手幢,會(huì)展示當(dāng)前進(jìn)程的信息捷凄,按ctrl+c
可以中斷執(zhí)行
3.2 thread
這個(gè)命令和jstack很相似,但是功能更加強(qiáng)大围来,主要看當(dāng)前JVM的線程堆棧信息
還可以結(jié)合使用thread -b來(lái)進(jìn)行死鎖排查跺涤。
參數(shù)解析
-h 顯示幫助
-n 指定最忙的前n個(gè)線程并打印堆棧
- -b 找出阻塞當(dāng)前線程的線程
這是沒(méi)有阻塞線程的效果
運(yùn)行一個(gè)死鎖代碼再試一下
出現(xiàn)死鎖匈睁,會(huì)有紅色字體提醒,這個(gè)阻塞的線程已經(jīng)被另外一個(gè)線程阻塞- -i 指定cpu占比統(tǒng)計(jì)的采樣時(shí)間間隔桶错,單位為毫秒
每隔1000毫秒進(jìn)行采樣航唆,顯示最占CPU時(shí)間的前2個(gè)線程
- --state 線程狀態(tài)
- <id> 顯示線程堆
先通過(guò)dashboard查到一個(gè)線程id
3.3 jvm
這個(gè)命令可以查看到非常詳細(xì)的jvm信息
3.4 jad
反編譯指定已加載類的源碼
[arthas@36092]$ jad sandwich.test10.StopWorld
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@631cd9f3
Location:
/D:/git/test/target/classes/
/*
* Decompiled with CFR.
*/
package sandwich.test10;
import java.util.LinkedList;
import java.util.List;
public class StopWorld {
public static void main(String[] args) {
FillListThread fillListThread = new FillListThread();
TimerThread timerThread = new TimerThread();
/*61*/ fillListThread.start();
/*62*/ timerThread.start();
}
public static class TimerThread
extends Thread {
public static final long startTime = System.currentTimeMillis();
@Override
public void run() {
while (true) {
try {
while (true) {
long t = System.currentTimeMillis() - startTime;
Thread.sleep(1000L);
}
}
catch (InterruptedException e) {
e.printStackTrace();
continue;
}
break;
}
}
}
public static class FillListThread
extends Thread {
List<byte[]> list = new LinkedList<byte[]>();
@Override
public void run() {
while (true) {
try {
while (true) {
if (this.list.size() * 512 / 1024 / 1024 >= 1000) {
System.out.println("Going to clear list, list size: " + this.list.size());
this.list.clear();
System.out.println("List is clean, list size: " + this.list.size());
}
for (int i = 0; i < 100; ++i) {
byte[] bytes = new byte[1024];
this.list.add(bytes);
}
Thread.sleep(1L);
}
}
catch (InterruptedException e) {
e.printStackTrace();
continue;
}
break;
}
}
}
}
Affect(row-cnt:3) cost in 221 ms.
3.5 trace
使用trace命令可以跟蹤統(tǒng)計(jì)方法耗時(shí)。
trace {class-pattern} {method-pattern} -n {命令執(zhí)行次數(shù)} --skipJDKMethod false
參數(shù)名稱 | 參數(shù)說(shuō)明 |
---|---|
class-pattern | 類名表達(dá)式匹配 |
method-pattern | 方法名表達(dá)式匹配 |
condition-express | 條件表達(dá)式 |
[E] | 開啟正則表達(dá)式匹配院刁,默認(rèn)為通配符匹配 |
[n:] |
命令執(zhí)行次數(shù) |
#cost |
方法執(zhí)行耗時(shí) |
這個(gè)命令就可以統(tǒng)計(jì)出來(lái)一個(gè)類里面的一些高耗時(shí)的方法
3.6 watch
watch讓你能方便的觀察到指定函數(shù)的調(diào)用情況糯钙。能觀察到的范圍為:返回值、拋出異常退腥、入?yún)⑷伟叮ㄟ^(guò)編寫 OGNL 表達(dá)式進(jìn)行對(duì)應(yīng)變量的查看
watch 的參數(shù)比較多,主要是因?yàn)樗茉?4 個(gè)不同的場(chǎng)景觀察對(duì)象
參數(shù)名稱 | 參數(shù)說(shuō)明 |
---|---|
class-pattern | 類名表達(dá)式匹配 |
method-pattern | 函數(shù)名表達(dá)式匹配 |
express | 觀察表達(dá)式狡刘,默認(rèn)值:{params, target, returnObj}
|
condition-express | 條件表達(dá)式 |
[b] | 在函數(shù)調(diào)用之前觀察 |
[e] | 在函數(shù)異常之后觀察 |
[s] | 在函數(shù)返回之后觀察 |
[f] | 在函數(shù)結(jié)束之后(正常返回和異常返回)觀察 |
[E] | 開啟正則表達(dá)式匹配享潜,默認(rèn)為通配符匹配 |
[x:] | 指定輸出結(jié)果的屬性遍歷深度,默認(rèn)為 1 |
剛開始監(jiān)聽是這樣的
當(dāng)方法被調(diào)用完才會(huì)打印出調(diào)用信息嗅蔬,以下是能過(guò)rest api call了兩次的信息
3.7 monitor
實(shí)時(shí)返回命令是輸入之后立即返回米碰,而非實(shí)時(shí)返回的命令,則是不斷的等待目標(biāo) Java 進(jìn)程返回信息购城,直到用戶輸入 Ctrl+C
為止吕座。
服務(wù)端是以任務(wù)的形式在后臺(tái)跑任務(wù),植入的代碼隨著任務(wù)的中止而不會(huì)被執(zhí)行瘪板,所以任務(wù)關(guān)閉后吴趴,不會(huì)對(duì)原有性能產(chǎn)生太大影響,而且原則上侮攀,任何Arthas命令不會(huì)引起原有業(yè)務(wù)邏輯的改變锣枝。
方法擁有一個(gè)命名參數(shù) [c:]
,意思是統(tǒng)計(jì)周期(cycle of output)兰英,擁有一個(gè)整型的參數(shù)值
參數(shù)名稱 | 參數(shù)說(shuō)明 |
---|---|
class-pattern | 類名表達(dá)式匹配 |
method-pattern | 方法名表達(dá)式匹配 |
condition-express | 條件表達(dá)式 |
[E] | 開啟正則表達(dá)式匹配撇叁,默認(rèn)為通配符匹配 |
[c:] |
統(tǒng)計(jì)周期,默認(rèn)值為120秒 |
[b] | 在方法調(diào)用之前計(jì)算condition-express |
監(jiān)控項(xiàng) | 說(shuō)明 |
---|---|
timestamp | 時(shí)間戳 |
class | Java類 |
method | 方法(構(gòu)造方法畦贸、普通方法) |
total | 調(diào)用次數(shù) |
success | 成功次數(shù) |
fail | 失敗次數(shù) |
rt | 平均RT |
fail-rate | 失敗率 |
3.8 vmoption
查看陨闹,更新JVM診斷相關(guān)的參數(shù)
[arthas@13412]$ vmoption
KEY VALUE ORIGIN WRITEABLE
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HeapDumpBeforeFullGC false DEFAULT true
HeapDumpAfterFullGC false DEFAULT true
HeapDumpOnOutOfMemoryError false DEFAULT true
HeapDumpPath DEFAULT true
CMSAbortablePrecleanWaitMillis 100 DEFAULT true
CMSWaitDuration 2000 DEFAULT true
CMSTriggerInterval -1 DEFAULT true
PrintGC false DEFAULT true
PrintGCDetails false DEFAULT true
PrintGCDateStamps false DEFAULT true
PrintGCTimeStamps false DEFAULT true
PrintGCID false DEFAULT true
PrintClassHistogramBeforeFullGC false DEFAULT true
PrintClassHistogramAfterFullGC false DEFAULT true
PrintClassHistogram false DEFAULT true
MinHeapFreeRatio 0 DEFAULT true
MaxHeapFreeRatio 100 DEFAULT true
PrintConcurrentLocks false DEFAULT true
UnlockCommercialFeatures false DEFAULT true
3.9 sc
查看JVM已加載的類信息,可以根據(jù)包名模糊查詢
[arthas@13412]$ sc com.alibaba.arthas.deps.ch.qos.logback.classic.*
com.alibaba.arthas.deps.ch.qos.logback.classic.BasicConfigurator
com.alibaba.arthas.deps.ch.qos.logback.classic.Level
com.alibaba.arthas.deps.ch.qos.logback.classic.Logger
com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext
com.alibaba.arthas.deps.ch.qos.logback.classic.PatternLayout
com.alibaba.arthas.deps.ch.qos.logback.classic.boolex.JaninoEventEvaluator
com.alibaba.arthas.deps.ch.qos.logback.classic.encoder.PatternLayoutEncoder
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.JoranConfigurator
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.ConfigurationAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.ConsolePluginAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.ContextNameAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.EvaluatorAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.InsertFromJNDIAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.JMXConfiguratorAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.LevelAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.LoggerAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.LoggerContextListenerAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.ReceiverAction
com.alibaba.arthas.deps.ch.qos.logback.classic.joran.action.RootLoggerAction
com.alibaba.arthas.deps.ch.qos.logback.classic.layout.TTLLLayout
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.Abbreviator
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.CallerDataConverter
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.ClassOfCallerConverter
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.ClassicConverter
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.ContextNameConverter
com.alibaba.arthas.deps.ch.qos.logback.classic.pattern.DateConverter
...
3.10 sm
查看已加載類的方法信息
[arthas@13412]$ sm com.alibaba.arthas.deps.ch.qos.logback.classic.Level
com.alibaba.arthas.deps.ch.qos.logback.classic.Level <init>(ILjava/lang/String;)V
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toString()Ljava/lang/String;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level valueOf(Ljava/lang/String;)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level readResolve()Ljava/lang/Object;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toLocationAwareLoggerInteger(Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;)I
com.alibaba.arthas.deps.ch.qos.logback.classic.Level fromLocationAwareLoggerInteger(I)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toLevel(I)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toLevel(Ljava/lang/String;Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toLevel(Ljava/lang/String;)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toLevel(ILcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;)Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toInt()I
com.alibaba.arthas.deps.ch.qos.logback.classic.Level toInteger()Ljava/lang/Integer;
com.alibaba.arthas.deps.ch.qos.logback.classic.Level isGreaterOrEqual(Lcom/alibaba/arthas/deps/ch/qos/logback/classic/Level;)Z
Affect(row-cnt:13) cost in 4 ms.
這些只是一些基礎(chǔ)命令薄坏,如果需要深入使用趋厉,還需要研究Arthas的進(jìn)階使用
4.通過(guò)瀏覽器連接arthas
Arthas目前支持Web Console,用戶在attach成功之后胶坠,可以直接訪問(wèn)
端口可以在啟動(dòng)信息里面確認(rèn)
可以填入IP君账,遠(yuǎn)程連接其它機(jī)器上的arthas,web console跟我本地訪問(wèn)的可以不相同
那我們要怎樣綁定其他端口和進(jìn)程呢沈善?
在遠(yuǎn)程服務(wù)器上啟動(dòng)arthas乡数,啟動(dòng)時(shí)要指定ip和端口椭蹄,不然不開放遠(yuǎn)程訪問(wèn),只能通過(guò)127.0.0.1訪問(wèn)
java -jar arthas-boot.jar --target-ip {ip} --http-port {port} {pid}
如下:
Web訪問(wèn)
5.Arthas idea插件
arthas-idea支持部分命令可視化
裝好插件之后就可以在類上面右鍵選擇命令了净赴,如下
選擇命令就已經(jīng)復(fù)制好命令和需要的參數(shù)了塑娇,然后去執(zhí)行這個(gè)命令