1. arthas简介
arthas 是一款用于java程序诊断的跨平台开源工具,由Alibaba开源、维护,集成了jvm跟踪查看、反编译、热更新、热加载、代码执行追踪等功能,方便开发者排查定位线上问题、调优等。
-
官方文档地址
-
github源码地址
官方文档中罗列出arthas可协助排查的场景如下:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
2. 安装与基本使用
2.1 下载与安装
github release:github.com/alibaba/art…
- 快速安装
# 下载jar包
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 第一次打开时,会下载关联包,下载速度慢,可使用aliyun镜像
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
- 安装shell命令
curl -L https://arthas.aliyun.com/install.sh | sh
该命令会下载启动脚本文件as.sh到当前目录,可配置环境变量快速启动
推荐采用快速安装方式,通过jar包方式启动更灵活,多平台之间的操作体验也是一致的。
2.2 基本使用
arthas以java进程作为基本的操作单元,启动arthas后,会列出所有的java进程,选择编号后,会启动一个arthas server,后续可创建多个会话连接到arthas server,连接上后,即可通过arthas提供的命令来对java进程进行诊断。
2.2.1 启动并连接到java进程
# 启动arthas
cd arthasPath
java -jar arthas-boot.jar
启动arthas后,会罗列出所有的java进程,及对应的编号
Arthas script version: 3.4.6
[INFO] JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home
[INFO] Process 3983 already using port 3658
[INFO] Process 3983 already using port 8563
Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 1795
[2]: 2484 com.intellij.database.remote.RemoteJdbcServer
[3]: 1828 org.jetbrains.jps.cmdline.Launcher
[4]: 533
[5]: 1290 com.intellij.database.remote.RemoteJdbcServer
[6]: 3982 org.jetbrains.jps.cmdline.Launcher
[7]: 3983 top.learningwang.arthasdemo.ArthasDemoApplication
输入想诊断的java进程对应的编号并按下enter键,等待arthas server创建,会话建立后,即可通过arthas命令进行操作
Attaching to 3983 using version /Users/wangjingbiao/software/arthas...
real 0m0.202s
user 0m0.369s
sys 0m0.045s
Attach success.
telnet connecting to arthas server... current timestamp is 1613983174
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
,---. ,------. ,--------.,--. ,--. ,---. ,---.
/ O \ | .--. ''--. .--'| '--' | / O \ ' .-'
| .-. || '--'.' | | | .--. || .-. |`. `-.
| | | || |\ \ | | | | | || | | |.-' |
`--' `--'`--' '--' `--' `--' `--'`--' `--'`-----'
wiki https://arthas.aliyun.com/doc
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html
version 3.4.6
pid 3983
time 2021-02-22 16:15:16
[arthas@3983]$
2.2.2 执行arthas命令
启动arthas会话后,即可输入执行arthas支持的命令。 目前支持的命令列表:arthas.aliyun.com/doc/command…
下文会详细展示常用命令、及特定场景的命令操作。
2.2.3 退出arthas
-
quit 退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
-
exit 等同于quit
-
stop 关闭 Arthas 服务端,所有 Arthas 客户端全部退出
3. arthas 常用命令
dashboard
-
功能 展示当前java进程的实时数据(线程、gc、jvm内存占用等)信息
-
命令使用示例
# 展示当前java进程 线程cpu占用、gc信息、jvm信息等,5s刷新一次
dashboard
# 刷新10次后终止,默认5s刷新一次
dashboard -n 10
# 2s刷新一次
dashboard -i 2000
# 2s刷新一次,共刷新10次
dashboard -i 2000 -n 10
# 2s刷新一次,共刷新10次,并保存到文件中,用于后续分析
dashboard -i 2000 -n 10 | tee /data/dashback_2021_02_21.txt
sysprop、sysenv、jvm
sysprop命令官方文档
sysenv命令官方文档
jvm命令官方文档
- 功能 sysprop:查看当前JVM的系统属性(System Property) sysenv:查看当前JVM的环境属性(System Environment Variables) jvm:查看当前jvm信息
# 查看jvm信息
jvm
# 查看当前jvm的所有系统属性
sysprop
# 查看具体的某个系统属性
sysprop java.class.version
# 模糊匹配某些系统属性
sysprop | grep java.class.
# sysenv用法同sysprop
thread
-
功能 展示当前java进程详细的线程信息
-
命令使用示例
# 展示所有的线程列表
thread
thread-all
# cpu使用率采样修改为2s,默认为200ms
thread -i 2000
# 打印出cpu使用率前5的线程详情,即比较繁忙的线程,cpu使用率采样统计方式请参考官方文档说明
thread -n 5
# 打印id为5的线程详情
thread 5
# 根据状态过滤线程数据(NEW, RUNNABLE, TIMED_WAITING, WAITING, BLOCKED, TERMINATED)
thread --state RUNNABLE
thread |grep RUNNABLE
# 列出持有某个锁,阻塞其他线程最多的线程,排查死锁
thread -b
classloader
-
功能 查看类加载器信息
-
命令使用示例
# 查看类加载器,及加载信息
classloader
# 查看类加载器hash、parent信息
classloader -l
# 查看类加载器之间的继承树
classloader -t
# 列出所有类加载器及加载的类
classloader -a
# 查看URLClassLoader实际的urls
classloader -c hashcode
sc
-
功能 查看jvm中某个类的信息
-
命令使用示例
# 模糊匹配类信息,支持正则表达式,如果是接口,还会列出所有的实现类
sc java.lang.String*
# 模糊匹配类信息,限制最多匹配到的数量,默认100
sc java.lang.String* -n 2
# 查看类详情信息
sc -d java.lang.String
# 指定类加载器查看类信息
sc -c hashcode java.lang.String*
# 查看类详情信息,包含field信息
sc -d -f java.lang.String
sm
-
功能 查询jvm中某个类的方法信息
-
命令使用示例
# 查看某个类下所有的方法信息
sm top.learningwang.arthasdemo.controller.VipUserController
# 查看某个类下的某个方法信息
sm top.learningwang.arthasdemo.controller.VipUserController dropVipUser
# 查看方法详情
sm -d top.learningwang.arthasdemo.controller.VipUserController dropVipUser
# 指定类加载器查看类下某个方法的详细信息
sm -c hashcode -d top.learningwang.arthasdemo.controller.VipUserController dropVipUser
monitor
-
功能 统计方法一段周期内的执行情况
-
命令使用示例
# 统计某个类某个方法的执行信息,默认60s为统计周期
monitor top.learningwang.arthasdemo.controller.VipUserController helloUser
# 统计某个类下某个方法的执行信息,10s为统计周期,统计3次
monitor top.learningwang.arthasdemo.controller.VipUserController helloUser -c 10 -n 3
# 统计某个类下某个方法的执行信息,限定参数值,5s为统计周期
monitor top.learningwang.arthasdemo.controller.VipUserController helloUser "params[0].length<5" -c 5
watch
-
功能 观测某方法执行的详情
-
命令使用示例
# 观测某方法的执行详情,支持ognl表达式输出观测结果
watch *VipUserController helloUser '{clazz,method,isReturn,isThrow,params,target,returnObj,throwExp}'
:<<!
常用表达式
target : the object
clazz : the object's class
method : the constructor or method
params : the parameters array of method
params[0..n] : the element of parameters array
returnObj : the returned object of method
throwExp : the throw exception of method
isReturn : the method ended by return
isThrow : the method ended by throwing exception
#cost : the execution time in ms of method invocation
!
# 限制观测执行次数
watch *VipUserController helloUser -n 2
# 设置观测结果遍历深度
wathch *VipUserController helloUser -x 2
# 只观测执行成功
watch *VipUserController helloUser -s
# 只观测执行失败
watch *VipUserController helloUser -e
# 同时观测方法执行前、方法执行后结果
watch *VipUserController helloUser -b -f
# 观测方法执行异常时,详细的异常栈信息
watch *VipUserController helloUser '{throwExp}' -e -x 2
# 观测方法执行时间大于200ms的信息
watch *VipUserController helloUser '#cost>100'
trace
-
功能 追踪方法内部调用路径,并输出方法路径上的每个节点上耗时(只会打印到第一层)
-
命令使用示例
# 观测方法内部调用顺序及耗时
trace top.learningwang.arthasdemo.controller.VipUserController helloUser
# 观测方法内部调用顺序及耗时,只观测3次
trace top.learningwang.arthasdemo.controller.VipUserController helloUser -n 3
# 观测方法内部调用顺序及耗时,包含jdk内部方法
trace top.learningwang.arthasdemo.controller.VipUserController helloUser --skipJDKMethod false
# 限制观测范围,第一个参数长度大于10
trace top.learningwang.arthasdemo.controller.VipUserController helloUser params[0].length>=10
# 限制观测范围,执行耗时大于100ms
trace top.learningwang.arthasdemo.controller.VipUserController helloUser '#cost>100'
# trace 同时多个类的多个方法
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
stack
-
功能 输出当前方法被调用的调用路径
-
命令使用示例
# 观测某方法的调用栈
stack top.learningwang.arthasdemo.service.VipUserService getVipUserByCardNo
# 观测某方法的调用栈,3次
stack top.learningwang.arthasdemo.service.VipUserService getVipUserByCardNo -n 3
# 观测某方法耗时大于100ms时的调用栈
stack top.learningwang.arthasdemo.service.VipUserService getVipUserByCardNo '#cost>100'
headdump
-
功能 生成headdump文件到执行目录,用于分析对象内存占用等问题。 常用分析headdump文件的软件:Eclipse Memory Analyzer(MAT)
-
命令使用示例
# 生成headdump文件到指定目录
heapdump /tmp/dump.hprof
# 只dump live对象
heapdump --live /tmp/dump.hprof
4. 场景实战
4.1 修改日志级别
目前存在web服务,日志级别为error,解决线上问题时,需要看info中打印的信息,来排查数据问题,可按照如下方式进行修改日志级别。
# 查找到具体的类信息
sc -d *VipUserController
# 使用ognl表达式查看日志属性的信息,判断日志级别
ognl -c classLoaderHash "@top.learningwang.arthasdemo.controller.VipUserController@logger"
# 使用ognl表达式修改日志级别
ognl -c classLoaderHash "@top.learningwang.arthasdemo.controller.VipUserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)"
# 再次查看日志级别,判断是否修改成功
ognl "@top.learningwang.arthasdemo.controller.VipUserController@logger"
# 修改全局日志级别
ognl -c classLoaderHash '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'
4.2 更新代码、热加载
线上代码有一行出现了问题,想不重启,修改代码后,实现热加载
# 反编译源码,并保存到文件中
jad --source-only top.learningwang.arthasdemo.controller.VipUserController > /data/VipUserController.java
编辑代码,修改hello为hello2
# 根据源码,编译出class文件,并保存到执行目录
mc -c 18b4aac2 /data/VipUserController.java -d /data/
# 重新加载编译好的class文件
redefine -c 18b4aac2 /data/top/learningwang/arthasdemo/controller/VipUserController.class
访问接口,测试热加载结果
4.3 排查函数调用异常
观测方法执行异常具体信息,入参、出参等
# 观测方法执行异常时,详细的异常栈信息
watch *VipUserController helloUser '{throwExp}' -e -x 2
4.4 arthas 后台异步执行诊断任务
执行dashboard、watch、trace等命令时,可将命令执行挂起,将结果输出到文件中,供后续分析,不影响其他命令执行。
# 后台执行dashboard,并输出结果到文件中
dashboard >> /data/dash.log &
# 查看当前执行中的后台任务
jobs
# 终止后台任务
kill jobid
4.5 排查方法执行效率问题
线上某个接口执行慢,无法确定是哪一段代码的问题。
# 观测某几个方法,执行耗时大于100ms的调用栈
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3 '#cost>100'
可根据各方法执行耗时,缩小排查范围。
5. 远程诊断
5.1 webConsole
启动arthas Server时,会默认启动webConsole服务,默认端口号 3658,对端口访问放开权限后,外部即可直接通过访问 http://ip:port方式在浏览器中远程执行arthas命令
5.2 tunnel server
arthas 提供了Springboot starter,配置到项目中后,启动项目时,会启动一个arthas tunnnel server
<!-- springboot 依赖-->
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-spring-boot-starter</artifactId>
<version>${arthas.version}</version>
</dependency>
启动服务后,网络可连通的情况下,即可实现arthas远程诊断
java -jar arthas-boot.jar 'ws://ip:port/ws'
附1:源码地址
演示命令时用到的springboot web服务源码