36k Star!Arthas Java开发者的故障排查利器

文摘   2024-10-31 09:09   辽宁  

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


[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时间戳
classJava 类
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


欢迎关注我的公众号“编程与架构”,原创技术文章第一时间推送。



编程与架构
专注于Java、大数据、AI以及开发运维技术的深入探索与分享。作为一名开源爱好者,致力于分享实战经验和前沿技术动态,帮助更多技术人提升技能。
 最新文章