使用Arthues分析高CPU问题

Arthas是阿里开源的 Java 诊断工具,相比 JDK 内置的诊断工具,要更人性化,并且功能强大,可以实现许多问题的一键定位,而且可以一键反编译类查看源码,甚至是直接进行生产代码热修复,实现在一个工具内快速定位和修复问题的一站式服务。今天,我们就来学习一下如何使用Arthas 定位一个 CPU 使用高的问题。

首先,下载并启动 Arthas:

curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar

启动后,直接找到我们要排查的 JVM 进程,然后可以看到 Arthas 附加进程成功:

$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.6.6
[INFO] Process 12024 already using port 3658
[INFO] Process 12024 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 12024 fcp.troubleshootingtools.arthas.HighCPUApplication
  [2]: 7476
  [3]: 18716 C:\Users\fuche\Desktop\MemoryAnalyzer\mat\\plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
  [4]: 23100 org.jetbrains.jps.cmdline.Launcher
1
[INFO] arthas home: C:\Users\fuche\.arthas\lib\3.7.0\arthas
[INFO] The target process already listen port 3658, skip attach.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'

wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.7.0
main_class
pid        12024
time       2023-08-16 19:56:06

输出 help 命令,可以看到所有支持的命令列表。也可以通过官方文档来查看这些命令的完整介绍。

1、使用dashboard展示所有线程、内存、GC 等情况,其输出如下:
使用Arthues分析高CPU问题_第1张图片
从dashboard中可以看出,CPU高并不是GC引起的,而是由于ForkJoinPool引起的,ForkJoinPool是并发流默认使用的线程池,因此问题可能是出现在某段并发流的代码上。

2、使用thread -n查看最繁忙的8个线程栈

thread -n 8

使用Arthues分析高CPU问题_第2张图片
可以看到这些线程是因为正在处理MD5操作,所以占用了大量的CPU资源。如果我们希望分析出代码中哪些逻辑可能会执行这个操作,所以需要从方法栈上找出我们自己写的类,并重点关注。也就是我们HighCPUApplication类的doTask方法

3、使用Jad命令对HighCPUApplication 类进行反编译
使用Arthues分析高CPU问题_第3张图片
可以看到调用路径是 main->task()->doTask(),当 doTask 方法接收到的 int 参数等于某个常量的时候,会进行 1 万次的 MD5 操作,这就是耗费 CPU 的来源。那么,这个魔法值到底是多少呢?

我们可以使用jad查看User类来知道这个魔法值是多少,但实际业务场景中判断逻辑不可能这么直白,在这种情况下如果我们还想知道doTask会慢在什么入参上怎么办呢?

4、使用watch命令监控耗时超过100ms的doTask方法的入参,并且输出入参,展开 2 层入参参数

watch fcp.troubleshootingtools.arthas.HighCPUApplication doTask '{params}' '#cost>100' -x 2

使用Arthues分析高CPU问题_第4张图片
可以看到,所有耗时较久的 doTask 方法的入参都是 0,意味着 User.ADMN_ID 常量应该是 0。

5、使用ognl命令执行一个表达式,验证User 类的 ADMIN_ID 静态字段是否为0

[arthas@29904]$ ognl '@fcp.troubleshootingtools.arthas.User@ADMIN_ID'
ognl '@fcp.troubleshootingtools.arthas.User@ADMIN_ID'
@Integer[0]

最后总结一下:

  1. 我们通过dashboard + thread可以快速定位出消耗CPU最多的线程以及方法栈
  2. 然后通过jad反编译相关代码来确定原因
  3. 此外我们可以借助watch观察当出现慢请求时,方法的入参是什么样的
  4. 以及使用ognl可以去查看一些字段的值

最后呢,可以到代码地址中下载相关代码,然后本地实践一下。以及本篇文章的内容实际上是学习自极客时间的《Java业务开发常见错误100例》这是一个实战性比较强的专栏,推荐大家也可以去看看

如果我们没有arthues或不允许使用arthues,可以参考这篇文章线上java程序CPU飙升问题排查

你可能感兴趣的:(问题排查,java,artheus,cpu,问题排查)