Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。官网:简介 | arthas
下载并启动 Arthas
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
启动后,会以序号列出所有的JVM进行,输入序号即可将Arthas attach 到该进程上,如下图所示,列出了6个java进程,输入3,则Arthas attach 到30725进程上
常用的命令
在Arthas attach 到你想要监控的进程上后,可以用下面的命令来进行一些操作
jad、thread、trace、watch、tt
jad
反编译指定已加载类的源码
场景:将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑。
还可以方便你确定服务器上的版本是不是你预期的版本,防止发错分支。
示例:反编译com.wukong.demo.MainController,你可以替换为自己的类
jad com.wukong.demo.MainController
thread
查看当前线程信息,查看线程的堆栈
场景:可以用于排查CPU占用率高的问题
参数说明
参数名称 | 参数说明 |
id | 线程 id |
[n:] | 指定最忙的前 N 个线程并打印堆栈 |
[b] | 找出当前阻塞其他线程的线程 |
[i <value>] | 指定 cpu 使用率统计的采样间隔,单位为毫秒,默认值为 200 |
[--all] | 显示所有匹配的线程 |
要查看最繁忙的线程在执行的线程栈,可以使用 thread -n 命令。这里,
示例1
直接thread命令查看所有的线程,并输出线程id,如下图所示
thread
比如1号线程CPU占用率最高,可以下面的命令查看该线程堆栈
thread 1
示例1
我们查看下CPU占用最高的 3 个线程:
thread -n 3
$ thread -n 3
"C1 CompilerThread0" [Internal] cpuUsage=1.63% deltaTime=3ms time=1170ms"arthas-command-execute" Id=23 cpuUsage=0.11% deltaTime=0ms time=401ms RUNNABLEat java.management@11.0.7/sun.management.ThreadImpl.dumpThreads0(Native Method)at java.management@11.0.7/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:466)at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:199)at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)at java.base@11.0.7/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)at java.base@11.0.7/java.util.concurrent.FutureTask.run(FutureTask.java:264)at java.base@11.0.7/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)at java.base@11.0.7/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)at java.base@11.0.7/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)at java.base@11.0.7/java.lang.Thread.run(Thread.java:834)"VM Periodic Task Thread" [Internal] cpuUsage=0.07% deltaTime=0ms time=584ms
trace
方法内部调用路径,并输出方法路径上的每个节点上耗时
场景:用于查看方法耗时大于一定时间的一些方法调用,方便查找耗时原因
示例:查看MainController getNameById方法执行时间大于1000ms的调用
说明:com.wukong.demo.MainController为类路径
getNameById 为接口方法名
-n 5 表示记录5次
--skipJDKMethod false 表示需要展示jdk里面的方法调用,trace 默认不会包含 jdk 里的函数调用
'#cost>1000' 表示耗时大于1000ms
trace com.wukong.demo.MainController getNameById -n 5 --skipJDKMethod false '#cost>1000'
watch
让你能方便的观察到指定函数的调用情况。能观察到的范围为:返回值、抛出异常、入参
场景:可用于排查在生产环境只有某些特定参数出错的情况,方便查看参数、返回值、异常,方便判断代码是哪里出问题了
示例:
查看MainController getNameById方法入参、返回值、异常
说明:
com.wukong.demo.Maincontroller 为类路径
getNameById 为要监控的方法名
'{params, returnobj,throwExp}' 查看参数、返回值、异常
-n 5 表示记录5次
-x 3 表示返回结果最多遍历深度为3,因为结果可能是一个复杂对象
watch com.wukong.demo.Maincontroller getNameById '{params, returnobj,throwExp}' -n 5 -x 3
tt
记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
场景:记录下当时方法调用的所有入参和返回值、抛出的异常,并可以进行重放,特别适合参数很复杂,复现比较麻烦的场景。
示例:
记录MainController getNameById方法5次调用情况,如下图所示,显示了每次调用的情况,并生产了序号 1000、1001、1002
tt -t com.wukong.demo.MainController getNameById -n 5
我想重新执行第三次请求,则使用下面的命令,1002为请求的序号
tt -p -i 1002