1.Arthas是什么
Arthas是Alibaba开源的Java诊断工具
他主要解决以下问题
1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
2.我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
3.遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
4.线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
5.是否有一个全局视角来查看系统的运行状况?
6.有什么办法可以监控到JVM的实时运行状态?
7.怎么快速定位应用的热点,生成火焰图?
8.怎样直接从JVM内查找某个类的实例?
更多细节请参考官网:https://arthas.aliyun.com/doc/
2.下载安装
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
启动后选择第一个进程进入,这里输入1选第一个进程
也可以通过jps查询到pid先,然后直接绑定pid和port
java -jar arthas-boot.jar --http-port {port} {pid}
3.常用命令
3.1 dashboard
输入dashboard,按回车/enter
,会展示当前进程的信息,按ctrl+c
可以中断执行
3.2 thread
这个命令和jstack很相似,但是功能更加强大,主要看当前JVM的线程堆栈信息
还可以结合使用thread -b来进行死锁排查。
参数解析
-h 显示帮助
-n 指定最忙的前n个线程并打印堆栈
- -b 找出阻塞当前线程的线程
这是没有阻塞线程的效果
运行一个死锁代码再试一下
出现死锁,会有红色字体提醒,这个阻塞的线程已经被另外一个线程阻塞- -i 指定cpu占比统计的采样时间间隔,单位为毫秒
每隔1000毫秒进行采样,显示最占CPU时间的前2个线程
- --state 线程状态
显示线程堆
先通过dashboard查到一个线程id
3.3 jvm
这个命令可以查看到非常详细的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 list = new LinkedList();
@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命令可以跟踪统计方法耗时。
trace {class-pattern} {method-pattern} -n {命令执行次数} --skipJDKMethod false
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[n:] |
命令执行次数 |
#cost |
方法执行耗时 |
这个命令就可以统计出来一个类里面的一些高耗时的方法
3.6 watch
watch让你能方便的观察到指定函数的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看
watch 的参数比较多,主要是因为它能在 4 个不同的场景观察对象
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 函数名表达式匹配 |
express | 观察表达式,默认值:{params, target, returnObj} |
condition-express | 条件表达式 |
[b] | 在函数调用之前观察 |
[e] | 在函数异常之后观察 |
[s] | 在函数返回之后观察 |
[f] | 在函数结束之后(正常返回和异常返回)观察 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[x:] | 指定输出结果的属性遍历深度,默认为 1 |
刚开始监听是这样的
当方法被调用完才会打印出调用信息,以下是能过rest api call了两次的信息
3.7 monitor
实时返回命令是输入之后立即返回,而非实时返回的命令,则是不断的等待目标 Java 进程返回信息,直到用户输入 Ctrl+C
为止。
服务端是以任务的形式在后台跑任务,植入的代码随着任务的中止而不会被执行,所以任务关闭后,不会对原有性能产生太大影响,而且原则上,任何Arthas命令不会引起原有业务逻辑的改变。
方法拥有一个命名参数 [c:]
,意思是统计周期(cycle of output),拥有一个整型的参数值
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[c:] |
统计周期,默认值为120秒 |
[b] | 在方法调用之前计算condition-express |
监控项 | 说明 |
---|---|
timestamp | 时间戳 |
class | Java类 |
method | 方法(构造方法、普通方法) |
total | 调用次数 |
success | 成功次数 |
fail | 失败次数 |
rt | 平均RT |
fail-rate | 失败率 |
3.8 vmoption
查看,更新JVM诊断相关的参数
[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已加载的类信息,可以根据包名模糊查询
[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 (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.
这些只是一些基础命令,如果需要深入使用,还需要研究Arthas的进阶使用
4.通过浏览器连接arthas
Arthas目前支持Web Console,用户在attach成功之后,可以直接访问
端口可以在启动信息里面确认
可以填入IP,远程连接其它机器上的arthas,web console跟我本地访问的可以不相同
那我们要怎样绑定其他端口和进程呢?
在远程服务器上启动arthas,启动时要指定ip和端口,不然不开放远程访问,只能通过127.0.0.1访问
java -jar arthas-boot.jar --target-ip {ip} --http-port {port} {pid}
如下:
Web访问
5.Arthas idea插件
arthas-idea支持部分命令可视化
装好插件之后就可以在类上面右键选择命令了,如下
选择命令就已经复制好命令和需要的参数了,然后去执行这个命令