在线调试工具 Arthas

在线调试工具 Arthas
强烈推介IDEA2020.2破解激活,IntelliJ IDEA 注册码,2020.2 IDEA 激活码

Arthas(阿尔萨斯) 是 Alibaba开源的 Java诊断工具,深受开发者喜爱。


当遇到以下类似问题而束手无策时,Arthas 可以帮助你解决:
【1】这个类从哪个 jar 包加载的? 为什么会报各种类相关的 Exception?
【2】我改的代码为什么没有执行到? 难道是我没 commit? 分支搞错了?
【3】遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
【4】线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
【5】是否有一个全局视角来查看系统的运行状况?
【6】有什么办法可以监控到 JVM的实时运行状态?

快速安装

运行环境要求:Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
执行如下命令:使用 curl命令从阿里服务器上下载对应的 arthas jar包,window和 Linux下均可执行。

1 C:\Users\86156>curl -O https://alibaba.github.io/arthas/arthas-boot.jar
2   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
3                                  Dload  Upload   Total   Spent    Left  Speed
4 100  133k  100  133k    0     0   1496      0  0:01:31  0:01:31 --:--:--  1707

启动:使用 java -jar 启动 arthas-boot.jar,来安装 arthas,大约 10M。需要注意在启动之前,必须启动至少一个 java程序,否则会自动退出。运行此命令会发现 java进程,输入需要 attach 粘附进程对应的序列号,例如,输入1按回车。则会监听该进程。

d:\DevSoft>java -jar arthas-boot.jar --repo-mirror aliyun --use-http
[INFO] arthas-boot version: 3.3.9
[INFO] Process 14464 already using port 3658
[INFO] Process 14464 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 14464
  [2]: 19092 org.jetbrains.jps.cmdline.Launcher
1
[INFO] arthas home: C:\Users\86156\.arthas\lib\3.4.0\arthas
[INFO] The target process already listen port 3658, skip attach.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'


wiki      https://arthas.aliyun.com/doc
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
version   3.4.0
pid       14464
time      2020-09-08 22:52:50

[arthas@14464]$

如果端口被占用了,也可以通过以下命令换成另一个端口号执行:

java -jar arthas-boot.jar --telnet-port 9922 --http-port -1

目录文件:下载的文件目录,可以从上面返回的信息获取,目录中的文件如下所示:

rm -rf ~/.arthas/
rm -rf ~/logs/arthas

常用命令接触

【dashboard 仪表板】

输入 dashboard(仪表板),会展示当前进程的信息,按 ctrl + c / q 可以中断执行。
【1】第一部分时显示 JVM中运行的所有线程:所在线程组,优先级,线程的状态,CPU的占有率,是否是后台进程等;
【2】第二部分显示的 JVM内存的使用情况;
【3】第三部分是操作系统的一些信息和 Java版本号;

【thread】

查看当前 jvm的线程堆栈信息。通过 thread 命令获取 arthas-demo 进程的主类。可以指定线程 ID,例如 thread tid参数说明:

参数名称 参数说明
数字 线程id
[n:] 指定最忙的前 N个线程并打印堆栈
[b] 找出当前阻塞其他线程的线程
[i <value>] 指定 cpu占比统计的采样间隔
[arthas@20584]$ thread -n 2
"main" Id=1 cpuUsage=100% RUNNABLE
    at com.zzx.demo.demo.main(demo.java:11)


"Reference Handler" Id=2 cpuUsage=0% WAITING on java.lang.ref.Reference$Lock@4f2d17e4
    at java.lang.Object.wait(Native Method)
    -  waiting on java.lang.ref.Reference$Lock@4f2d17e4
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

【jad】

通过 jad来反编译 Main Class。例如:jad 包名.类名 或者只反编译某个方法:jad 包名.类名 方法名或者只查看某个类的源码,不看类加载器等:jad 包名.类名 --source-only

【watch】

监视:来查看函数的返回值。watch 包名.类名 方法 返回值(OGNL表达式)。作用:方法执行数据观测,让你能方便的观察到指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL表达式进行对应变量的查看。watch 的参数比较多,主要是因为它能在 4个不同的场景观察对象。

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
express 观察表达式
condition-express 条件表达式
[b] 在方法调用之前观察 before
[e] 在方法异常时候观察 exception
[s] 在方法返回之后观察 success
[f] 在方法结束之后(正常返回和异常返回)观察 finish
[E] 开启正则表达式匹配,默认为通配符匹配
[x:] 指定输出结果的属性遍历深度,默认为1

这里重点要说明的是观察表达式,观察表达式的构成主要由 ognl 表达式组成,所以可以这样写 "{params,returnObj}",只要是一个合法的 ognl表达式,都能被正常支持。
特别说明:【1】watch 命令定义了 4个观察事件点,即 -b方法调用前,-e 方法异常后, -s 方法返回后,-f 方法结束后;
【2】4个观察事件点 -b,-e,-s默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出;
【3】这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b事件点 params代表方法入参外,其余事件都代表方法出参;
【4】当使用 -b时,由于观察事件点是在方法调用前,此时返回值或异常均不存在;

举例一:观察 demo.MathGame类中 primeFactors 方法出参和返回值,结果属性遍历深度为2。列举了执行时间正则表达式的返回值

基础命令

Linux中的命令在 Arthas中可以使用;

【1】session:查看当前会话的信息。

1 # 还原指定类
2 reset Test
3 #还原所有 List结尾的类
4 reset *List
5 #还原所有类
6 reset

效果:

 class / classloader 相关命令:方便在运行的过程中来诊断代码,查看错误。
【1】jad 把字节码文件反编译成源代码;

#1、使用 jad 反编译类文件 [demo.MathGame] 输出到 /root/MathGame.java
jad --source-only demo.MathGame > /root/MathGame.java

【2】mc 在内存中把源代码编译成字节码文件;

# 2、上面的代码编辑完毕以后,使用 mc 对新的代码进行编译,并指定编译完之后的路径
[arthas@16866]$ mc /root/MathGame.java -d /root
Memory compiler output:
/root/demo/MathGame.class
Affect(row-cnt:1) cost in 377ms

【3】redefine 把新生成的字节码文件加载到内存中执行;

#3、使用 redefine 命令加载新的字节码
redefine /root/demo/MathGame.class  # redefine 类的全路径

【4】sc:Search Class 查看运行中的类信息;
【5】sm:Search Method 查看运行中方法的信息;
【6】dump:将加载类的字节码文件保存到特定目录:logs/arthas/classdump/,不同的类加载器放在不同的目录下。

#把 String 类的字节码保存到 /logs/arthas/classdump
dump java.lang.String
#将 demo包下的所有类的字节码文件保存到 /logs/arthas/classdump/目录下
dump demo.*

【7】classloader:获取类加载器的信息。① classloader 命令将 JVM 中所有的 classloader的信息统计出来,并可以展示继承树,urls等。② 可以让指定的 classloader 去 getResources,打印出所有查找到的 resource 的url。对于 ResourceNotFoundException 异常比较有用。

参数名称 参数说明
[I] 按类加载实例进行统计
[t] 打印所有 ClassLoader的继承树
[a] 列出所有 ClassLoader加载的类,请谨慎使用
[c:] ClassLoader 的 hashcode
[c: r:] 用 ClassLoader 去查找 resource
[c: load:] 用 ClassLoader 去加载指定的类

monitor/trace相关

请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 shutdown 或将增强过的类执行 reset 命令。

【monitor】

monitor 命令:监控指定类中方法的执行情况。对匹配 class-pattern / method-pattern 的类,方法的调用进行监控。monitor 命令是一个非实时返回命令,实时返回命令是输入之后立即返回。而非实时返回命令,则是不断的等待目标 Java进行返回信息,直到用户输入 ctrl+c 为止。

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
[E] 开启正则表达式匹配,默认为通配符匹配
[c:] 统计周期,默认值为 120秒
# 每 5s 监控一次
monitor 包.类 方法名 -c 5

【trace】

对方法内部调用路径进行追踪,并输出方法路径上的每个节点上的耗时。trace 命令能主动搜索 class-pattern / method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。观察表达式的构成主要由 ognl表达式组成,所以你可以写成 “{params,returnObj}”,只要是一个合法的 ognl表达式,都能被正常支持。很多时候我们只想看到某个方法的 rt大于某个时间之后的 trace结果,现在 Arthas可以按照方法执行的耗时来进行过滤,例如:trace *StringUtils isBlank '#cost>100'表示当执行时间超过 100ms的时候,才会输出结果。 watch/stack/trace 这三个命令都支持 #cost 耗时条件过滤。也可以用正则表匹配路径上的多个类和函数,一定程度上达到多层 trace的效果:trace -E com.test.ClassA|org.test.ClassB method1|method2。

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 方法表达式匹配
condition-express 条件表达式,使用OGNL表达式
[E] 开启正则表达式,默认是通配符匹配
[n:] 命令执行次数
#cost 方法执行耗时,单位是毫秒

样例一:trace 函数指定类的指定方法;

【stack】

输出当前方法被调用的调用路径。很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从哪里被执行了,此时你就需要的是 stack命令。

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 方法名表达式匹配
condition-express 条件表达式,OGNL
[E] 开启正则表达式匹配,默认为通配符匹配
[n:] 执行次数限制

样例一:查看方法的调用路径;

【tt】

time-tunnel 时间隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同时间下调用的信息进行观测。

watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高,因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。这个时候要是能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。于是乎,TimeTunnel 命令就诞生了。

tt 的参数 说明
-t 记录某个方法在一个时间段中的调用。方法的每次执行情况。
-l 显示所有已经记录的列表
-n 次数 只记录多少次
-s 表达式 搜索表达式
-i 索引号 查看指定索引号的详细调用信息
-p 重新调用指定的索引号时间碎片

【profiler 火焰图】

profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。命令基本运行结构是 profiler 命令 [命令参数] 

#启动 profiler
$ profiler start

 当使用profiler  stop 停止之后,就会给 arthas-output文件中生成一个火焰图,如下:通过 --format html可以指定输出的格式;

profiler 命令作用
profiler start 启动 profiler,默认情况下,生产 cpu的火焰图
profiler list 显示所有支持的事件
profiler getSamples 获取已采集的 sample的数量
profiler status 查看 profiler的状态,运行时间
profiler stop 停止 profiler,生成火焰图的结果集,指定输出目录和输出格式:svg或html
本文来源程序猿进阶,由javajgs_com转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/8224

发表评论