36k Star!Arthas Java开发者的故障排查利器
Arthas 是 Alibaba 开发的强大 Java 诊断工具,提供了一系列实用的命令用于探查和优化 Java 应用的运行情况。本文将带您详细了解如何使用 Arthas 进行分析、诊断和优化 Java 应用,以便快速定位并解决性能瓶颈和应用故障。
Arthas 与其他工具对比
快速启动 Arthas
在启动 Arthas 过程中,我们可以选择需要分析的进程。选择 Java 进程后,Arthas 将自动下载并附加到指定进程上。
$ java -jar arthas-boot.jar --repo-mirror aliyun --use-http
[INFO] JAVA_HOME: /opt/jdk1.8.0_151/jre
* [1]: 11490 kafka.Kafka
1
[INFO] arthas-client connect 127.0.0.1 3658
...
pid 11490
[arthas@11490]$
Arthas 启动后,可直接通过命令行或 Web 界面(http://localhost:3658)进行操作。
Dashboard 监控
Dashboard 提供了 Java 应用的 CPU、内存、线程等运行状态的实时监控,方便快速定位问题所在。
输入dashborad
[arthas@11490]$ dashborad
查看 CPU 占用线程
当应用负载过高时,我们可以用 thread -n
命令查看占用 CPU 比较高的线程:
此命令将列出 CPU 占用率最高的两个线程,帮助我们识别出 CPU 密集型线程及其具体操作。
找出当前阻塞其他线程的线程
在 Java 应用中,可能存在某些线程阻塞其他线程的情况。thread -b
命令可以帮助我们快速定位阻塞线程。
注意, 目前只支持找出 synchronized 关键字阻塞住的线程, 如果是
java.util.concurrent.Lock
, 目前还不支持。
类进行反编译
比如我们通过Arthas分析到某一个类有问题,我们想看类的代码是什么,可以使用该方法。
[arthas@11490]$ jad org.apache.kafka.common.network.Selector
查看类的基础信息
sc -d ${类名}
查看类调用方法的堆栈信息
我们可以使用 stack
命令,实时追踪指定类的方法调用堆栈,找出调用链和执行顺序。当有方法调用了org.apache.kafka.common.network.Selector select
就会打印出详细信息
[arthas@11490]$ stack org.apache.kafka.common.network.Selector select
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 1332 ms, listenerId: 2
ts=2024-10-28 21:36:14.166;thread_name=ReplicaFetcherThread-0-1001;id=297787;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@764c12b6
@org.apache.kafka.common.network.Selector.select()
at org.apache.kafka.common.network.Selector.poll(Selector.java:409)
at org.apache.kafka.clients.NetworkClient.poll(NetworkClient.java:510)
at org.apache.kafka.clients.NetworkClientUtils.isReady(NetworkClientUtils.java:41)
at org.apache.kafka.clients.NetworkClientUtils.awaitReady(NetworkClientUtils.java:64)
at kafka.server.ReplicaFetcherBlockingSend.sendRequest(ReplicaFetcherBlockingSend.scala:91)
at kafka.server.ReplicaFetcherThread.fetch(ReplicaFetcherThread.scala:240)
at kafka.server.ReplicaFetcherThread.fetch(ReplicaFetcherThread.scala:43)
at kafka.server.AbstractFetcherThread.processFetchRequest(AbstractFetcherThread.scala:149)
at kafka.server.AbstractFetcherThread.doWork(AbstractFetcherThread.scala:114)
at kafka.utils.ShutdownableThread.run(ShutdownableThread.scala:82)
分析哪些方法执行慢
使用 trace
命令可以追踪方法的执行情况,分析哪些方法在执行中消耗了较多时间,从而定位性能瓶颈。
监听某一个方法的返回值
通过 watch
命令可以监听指定方法的返回值,例如:
[arthas@11490]$ watch org.apache.kafka.common.network.Selector select
此命令会在每次 select
方法执行完成时,返回其结果数据,以供调试。
method=org.apache.kafka.common.network.Selector.select location=AtExit
ts=2024-10-28 21:41:11.760; [cost=0.26099ms] result=@ArrayList[
@Object[][isEmpty=false;size=1],
@Selector[org.apache.kafka.common.network.Selector@3c7b65a1],
@Integer[1],
]
method=org.apache.kafka.common.network.Selector.select location=AtExit
ts=2024-10-28 21:41:11.761; [cost=0.04802ms] result=@ArrayList[
@Object[][isEmpty=false;size=1],
@Selector[org.apache.kafka.common.network.Selector@3c7b65a1],
@Integer[1],
]
获取运行中类的的字段
调用静态函数:
$ ognl '@java.lang.System@out.println("hello")'
null
获取静态类的静态字段:
$ ognl '@demo.MathGame@random'
@Random[
serialVersionUID=@Long[3905348978240129619],
seed=@AtomicLong[125451474443703],
multiplier=@Long[25214903917],
addend=@Long[11],
mask=@Long[281474976710655],
DOUBLE_UNIT=@Double[1.1102230246251565E-16],
BadBound=@String[bound must be positive],
BadRange=@String[bound must be greater than origin],
BadSize=@String[size must be non-negative],
seedUniquifier=@AtomicLong[-3282039941672302964],
nextNextGaussian=@Double[0.0],
haveNextNextGaussian=@Boolean[false],
serialPersistentFields=@ObjectStreamField[][isEmpty=false;size=3],
unsafe=@Unsafe[sun.misc.Unsafe@28ea5898],
seedOffset=@Long[24],
]
执行多行表达式,赋值给临时变量,返回一个 List:
$ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
@ArrayList[
@String[/opt/java/8.0.181-zulu/jre],
@String[OpenJDK Runtime Environment],
]
方法执行监控
监控维度说明:
监控项 | 说明 |
timestamp | 时间戳 |
class | Java 类 |
method | 方法(构造方法、普通方法) |
total | 调用次数 |
success | 成功次数 |
fail | 失败次数 |
rt | 平均 RT |
fail-rate | 失败率 |
环境变量与系统属性查看
在 Java 应用中,系统属性和环境变量影响着应用的运行配置。Arthas 提供了 sysenv
和 sysprop
命令以供查看和修改。
查看环境变量
sysenv
查看单个环境变量
$ sysenv USER
USER=admin
查看当前 JVM 的系统属性(System Property
)
sysprop
查看,修改单个属性
支持通过
TAB
键自动补全
$ sysprop user.country
user.country=US
$ sysprop user.country CN
Successfully changed the system property.
user.country=CN
火焰图生成-profiler
启动 profiler
默认情况下,生成的是 cpu 的火焰图,即 event 为
cpu
。可以用--event
参数指定其他性能分析模式,参考:https://arthas.aliyun.com/doc/profiler.html#profiler-%E6%94%AF%E6%8C%81%E7%9A%84-events。
$ profiler start
Started [cpu] profiling
获取已采集的 sample 的数量
$ profiler getSamples
23
查看 profiling 状态
$ profiler status
[cpu] profiling is running for 4 seconds
停止 profiler
生成火焰图格式结果
默认情况下,结果是 Flame Graph在新窗口打开 格式的 html
文件,也可以用 -o
或 --format
参数指定其他内容格式,包括 flat、traces、collapsed、flamegraph、tree、jfr。
$ profiler stop --format flamegraph
profiler output file: /tmp/test/arthas-output/20211207-111550.html
OK
在--file
参数指定的文件名后缀为 html
或 jfr
时,文件格式可以被推断出来。比如--file /tmp/result.html
将自动生成火焰图。
效果如下
常见问题
target process not responding or HotSpot VM not loaded
[ERROR] Start arthas failed, exception stack trace:
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)
at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:102)
at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27)
at com.taobao.arthas.core.Arthas.main(Arthas.java:161)
[ERROR] attach fail, targetPid: 11490
原因:
Java程序运行用户与arthas运行用户不一致
官网:https://arthas.aliyun.com/
GitHub:https://github.com/alibaba/arthas
欢迎关注我的公众号“编程与架构”,原创技术文章第一时间推送。