一、介绍
Arthas是阿里的一款开源Java诊断工具。
官方地址:https://arthas.aliyun.com/doc/
下载地址:https://arthas.aliyun.com/doc/download.html
二、安装启动
安装
windwos:
通过下载页面从mave仓或者github链接进行下载。
linux:
wget https://arthas.gitee.io/arthas-boot.jar
启动命令
Arthas 只是一个 java 程序,所以可以直接用 java -jar
运行。
#windows
java -jar arthas-boot.jar
#linux
java -jar arthas-boot.jar 或者 ./as.sh
注:机器上有java进程才能启动成功
打印帮助信息:
java -jar arthas-boot.jar -h
选择进程序列号
启动成功后根据获取到的java进程,选择要监测的 Java 进程的序列号【1】、【2】等。
在出现 Arthas Logo 之后就可以使用命令进行问题诊断了。
webconsole
成功启动连接进程之后就已经自动启动,可以直接访问 http://127.0.0.1:8563/ 访问,页面上的操作模式和控制台完全一样。
退出
使用 shutdown 退出时 Arthas 同时自动重置所有增强过的类 。
其他启动方式
# 运行方式1,先运行,再选择 Java 进程 PID
java -jar arthas-boot.jar
# 选择进程(输入[]内编号(不是PID)回车)
[INFO] arthas-boot version: 3.1.4
[INFO] Found existing java process, please choose one and hit RETURN.
* [1]: 11616 com.Arthas
[2]: 8676
[3]: 16200 org.jetbrains.jps.cmdline.Launcher
[4]: 21032 org.jetbrains.idea.maven.server.RemoteMavenServer
# 运行方式2,运行时选择 Java 进程 PID
java -jar arthas-boot.jar [PID]
查看java进程:
linux可以用ps命令查看
windows用jps命令查看,如下:
# 查看运行的 java 进程信息
$ jps -mlvV
# 筛选 java 进程信息
$ jps -mlvV | grep [xxx]
其他的启动方式请参考:https://arthas.aliyun.com/doc/download.html
三、常用命令
常用命令
下面列举一些 Arthas 的常用命令,看到这里你可能还不知道怎么使用,别急,后面会一一介绍。
命令 | 介绍 | 其他 |
---|---|---|
dashboard | 当前系统的实时数据面板 | |
thread | 查看当前 JVM 的线程堆栈信息 | |
watch | 方法执行数据观测 | |
trace | 方法内部调用路径,并输出方法路径上的每个节点上耗时 | |
stack | 输出当前方法被调用的调用路径 | |
tt | 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测 | |
monitor | 方法执行监控 | |
jvm | 查看当前 JVM 信息 | |
vmoption | 查看,更新 JVM 诊断相关的参数 | |
sc | 查看 JVM 已加载的类信息 | #查看某个类的字段 sc -d -f com.Arthas |
sm | 查看已加载类的方法信息 | #查看某个类的方法 sm com.Arthas |
jad | 反编译指定已加载类的源码 | # 反编译只显示源码 jad --source-only com.Arthas # 反编译某个类的某个方法 jad --source-only com.Arthas mysql |
ognl | 查看变量中的值 | #查看静态变量 hashSet 信息 ognl '@com.Arthas@hashSet' #查看静态变量 hashSet 大小 ognl '@com.Arthas@hashSet.size()' #对变量中的值进行操作 ognl '@com.Arthas@hashSet.add("test")' ognl '@com.Arthas@hashSet' |
classloader | 查看 classloader 的继承树,urls,类加载信息 | |
heapdump | 类似 jmap 命令的 heap dump 功能 |
全局监控
arthas启动后,输入dashboard,可以概览程序的 线程、内存、GC、运行环境信息。
四、常见线上问题排查
CPU使用率过高排查
通过dashboard概览可以看到有一个线程的CPU使用率非常高。
dashboard是动态的不方便定位,可以输入命令 *thread *查看所有线程信息。
输入命令:thread 14,查看具体的线程内容,14是thread面板中高耗CPU线程的id。
输入命令:** jad devtao.Arthas** ,反编译有问题的java类进行查看,jad命令后加thread中判断有问题的java类
找到代码的第66行,发现是一个while true的循环,至此找到问题根源。
线程问题排查
线程池状态
定位线程问题之前,先回顾一下线程的几种常见状态:
- RUNNABLE 运行中
- TIMED_WAITING 调用了以下方法的线程会进入TIMED_WAITING:
- Thread#sleep()
- Object#wait() 并加了超时参数
- Thread#join() 并加了超时参数
- LockSupport#parkNanos()
- LockSupport#parkUntil()
- WAITING 当线程调用以下方法时会进入WAITING状态:
- Object#wait() 而且不加超时参数
- Thread#join() 而且不加超时参数
- LockSupport#park()
- BLOCKED 阻塞,等待锁
Waitting线程处理
thread
thread **当线程太多的时候,可以用grep命令,thread |grep xxx**,xxx是线程名称的关键字(区分大小写),过滤显示关键线程。
thread 序号
找到需要排查的线程,thread 17,17是线程在arths中的序号,可以看到有TIMED_WAITTING的线程,Arthas的47行代码sleep了。
jad 类名
查看代码定位问题jad devtao.Arthas,jad命令后devtao.Arthas是类名
可以看到47行Thread.Sleep()方法触发TIME_WAITING状态了。
死锁(Blocked)线程处理
thread -b
判断死锁线程除了用thread命令查看线程的状态外,还可以直接使用 thread -b 命令查看直接定位到死锁信息。
jad 类名
看到死锁出现在Arthas.java 128行,反编译:jad devtao.Arthas
128行,可以看到Thread.currentThread()引起的死锁,因为代码里的线城池是1,两个线程抢占资源所以引起死锁。
线上问题需要具体的根据代码上下文进行排查。
程序运行问题排查
追踪方法耗时
使用 trace 命令可以跟踪统计方法耗时。
如下代码统计/user接口的耗时,即统计devtao.controller.UserController#getUser的耗时,代码如下:
执行命令:*trace devtao.controller.UserController getUser , *格式:trace 类名 方法名
执行trace命令之后,可以看到该方法每次被调用所花费的时间。如该例,可以看到是devtao.service.impl.UserServiceImpl#get方法耗时比较多,再追踪此方法的耗时,
执行命令:trace devtao.service.impl.UserServiceImpl get
可以看到service的get方法中每个调用的用时,check方法0.0133ms,servcie 0.0834ms,redis 0.2152ms,mysql 5.5872ms。
统计方法耗时
每5秒统计一下UserServiceImpl的get方法耗时,
** monitor -c 5 devtao.service.impl.UserServiceImpl get**
可以看到每5秒内该方法一共被调用多了多少次,平均耗时。
查看方法信息
使用 watch 命令轻松查看输入输出参数以及异常等信息。输入wathc -h查看使用帮助:
[arthas@101192]$ watch -h
USAGE:
watch [-b] [-e] [--exclude-class-pattern <value>] [-x <value>] [-f] [-h] [-n <value>] [--listenerId <value>] [-E] [-M <value>] [-s] [-v] class-pattern method-pattern [express] [condition-express]
SUMMARY:
Display the input/output parameter, return object, and thrown exception of specified method invocation
The express may be one of the following expression (evaluated dynamically):
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
Examples:
watch org.apache.commons.lang.StringUtils isBlank
watch org.apache.commons.lang.StringUtils isBlank '{params, target, returnObj, throwExp}' -x 2
watch *StringUtils isBlank params[0] params[0].length==1
watch *StringUtils isBlank params '#cost>100'
watch -f *StringUtils isBlank params
watch *StringUtils isBlank params[0]
watch -E -b org\.apache\.commons\.lang\.StringUtils isBlank params[0]
watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
常用的watch举例:
# 查看入参和出参
$ watch com.Arthas addHashSet '{params[0],returnObj}'
# 查看入参和出参大小
$ watch com.Arthas addHashSet '{params[0],returnObj.size}'
# 查看入参和出参中是否包含 'count10'
$ watch com.Arthas addHashSet '{params[0],returnObj.contains("count10")}'
# 查看入参和出参,出参 toString
$ watch com.Arthas addHashSet '{params[0],returnObj.toString()}'
查看方法的调用路径
使用 stack命令查看方法的调用信息。
# 观察类devtao.service.imp.UserServiceImpl的 mysql 方法调用路径
stack devtao.service.impl.UserServiceImpl mysql
记录方法执行的详细情况
tt -t devtao.service.impl.UserServiceImpl get ,格式为:tt -t 类名 方法名
可以看到记录中 INDEX=1000、1001、1002 的记录的 IS-EXP = true ,说明调用出现异常。
查看记录的方法调用信息:tt -l
查看调用记录的详细信息(-i 指定 INDEX):tt -i 1001
可以看到 INDEX=1001 的记录的异常信息。
重新发起调用,使用指定记录,使用 -p 重新调用:tt -i 1001 -p