最近团队在研究线上问题排查方式,发现线上存在CPU飙升问题,测试环境无法复现,查阅资料发现 Arthas 能够分析此类问题。
Arthas,开源的Java诊断工具。
那么Arthas能帮我们做什么事情呢?详细的用法大家可以查官方文档,这里带大家实践。
可以监控到JVM的实时的运行状态;
可以实时查看系统的运行状况;
遇到线上高流量系统,没有打日志,同时不能debug,线下却又不能重现,可以无须重启在线查看类方法输入输出,如同日志一般;
怀疑代码没有commit就发布了,它帮你在线查看;
......
这里推荐快速简单的安装方法,大家也可下载包安装。
curl -O https://arthas.aliyun.com/arthas-boot.jar --下载jar包
java -jar arthas-boot.jar --启动
java -jar arthas-boot.jar -h --查看帮助
正常上面操作就已经能够监听Java进程,但是我的项目用的Docker部署需要把 arthas 整合到镜像内,Dockerfile 文件如下
...
# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
...
如果你用的是JRE那么用的时候,肯定会有 tool.jar找不见的异常。
所以在打镜像的时候需要选择jdk,具体可以看官方文档。
https://arthas.aliyun.com/doc/docker.html
我所做的项目用了自己的基础镜像,暂时无法在打镜像的时候引入JDK,这就需要特殊处理下,步骤如下:
1、在Linx本地JDK目录如下
[root@master jdk1.8.0_221]# pwd
/home/jdk1.8.0_221
2、找到运行的容器
[root@master jdk1.8.0_221]# docker ps | grep hms
fcf3c7aed879 hub.codingce.com/codingce-dev/codingce-hms "/bin/sh -c 'java -X…" About an hour ago Up About an hour k8s_codingce-health_codingce-health-87f8bdf66-6lxd9_default_225daeaa-abd4-4591-a827-36ad6b36f50f_8
6270d035c617 hub.codingce.com/codingce-dev/codingce-hms-web "/docker-entrypoint.…" 2 days ago Up 2 days k8s_health2-web_health2-web-7ddbb7cdd5-xxwbn_sci-edas_da7d65c9-9c54-4445-8ecb-678bee853ab2_0
[root@master jdk1.8.0_221]#
本地JDK复制到容器中
docker cp jdk1.8.0_221/ de37f7e97560:/opt/java
然后就可以进入容器启动Arthas。
[root@master jdk1.8.0_221]# docker exec -it fcf3c7aed879 bash
root@codingce-87f8bdf66-6lxd9:/#
root@codingce-87f8bdf66-6lxd9:/opt# ls
arthas java
root@codingce-87f8bdf66-6lxd9:/opt# cd arthas/
root@codingce-87f8bdf66-6lxd9:/opt/arthas# ls
arthas-agent.jar arthas-boot.jar arthas-client.jar arthas-core.jar arthas-spy.jar arthas.properties as-service.bat as.bat as.sh async-profiler install-local.sh lib logback.xml math-game.jar
root@codingce-87f8bdf66-6lxd9:/opt/arthas#
运行Arthas。
root@codingce-87f8bdf66-6lxd9:/opt/arthas# /opt/java/jre/bin/java -jar arthas-boot.jar
[INFO] JAVA_HOME: /opt/java/jre
[INFO] arthas-boot version: 3.7.1
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 6 hms.jar
星号代表选中的进程。
[INFO] arthas home: /opt/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.1
main_class
pid 6
time 2023-11-05 15:57:09
[arthas@6]$
可以查看系统的整体情况如下图:线程、内存、系统运行时信息等
JVM全景报表
帮助你分析现有系统情况,类加载情况,线程情况,系统内存情况等等如下图:并未截取全部。
thread 查看当前线程
thread id 查看指定线程id 的堆栈
thread -n 2 查看cpu最忙的前2个线程
thread -b, 找出当前阻塞其他线程的线程
thread -n 2 -i 1000 列出1000ms内最忙的2个线程堆栈
thread -b
,找出当前阻塞其他线程的线程。
有时候发现服务卡住了, 一般情况是:
某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成阻塞。这个命令可以解决。
线上没有打日志,同时不能debug,线下却又不能重现,watch命令可以无须重启在线查看类方法输入输出,如同日志一般。
能观察到的方法监测的数据范围:返回值、抛出异常、入参。
watch demo.MathGame primeFactors "{params,returnObj}" -x 4
观察 demo.MathGame.primeFactors 的入参 和 返回值 遍历深度4
[arthas@6]$ watch com.codingce.health.service.impl.HealthAssessmentReportServiceImpl pageVo "{params,returnObj}" -x 4
你有时候有这样的疑惑,现在运行的代码是我提交的代码吗?虽然master有,但是线上运行的包是这个master打的吗?它可以直接在线反编译。
jad demo.MathGame 反编译demo.MathGame
jad --source-only demo.MathGame 反编译demo.MathGame只展示源码
jad demo.MathGame main 反编译demo.MathGame main函数
jad demo.MathGame --classLoaderClass sun.misc.Launcher$AppClassLoader 指定classloader,用于多个classloader加载的情况
跟踪方法内部调用路径,并输出方法路径上的每个节点上耗时。
trace demo.MathGame run 追踪demo.MathGame run 方法
trace demo.MathGame run -n 1 追踪demo.MathGame run 方法只1次即退出
trace demo.MathGame run '#cost > 10' 追踪大于10ms的
[arthas@6]$ trace cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl pageVo
Press Q or Ctrl+C to abort.
Affect(class count: 2 , method count: 2) cost in 500 ms, listenerId: 2
`---ts=2023-11-05 17:37:44;thread_name=XNIO-1 task-4;id=6c;is_daemon=false;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@345f69f3
`---[54.506314ms] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl$$EnhancerBySpringCGLIB$$ef541:pageVo()
`---[99.69% 54.339228ms ] org.springframework.cglib.proxy.MethodInterceptor:intercept()
`---[79.59% 43.248517ms ] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl:pageVo()
`---[98.15% 42.448222ms ] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl:pageCommon() #781
`---ts=2023-11-05 17:37:49;thread_name=XNIO-1 task-26;id=8a;is_daemon=false;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@345f69f3
`---[24.51515ms] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl$$EnhancerBySpringCGLIB$$ef541:pageVo()
`---[99.81% 24.46882ms ] org.springframework.cglib.proxy.MethodInterceptor:intercept()
`---[72.11% 17.643921ms ] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl:pageVo()
`---[99.86% 17.619807ms ] cn.com.codingce.service.impl.HealthAssessmentReportServiceImpl:pageCommon() #781
查看JVM已加载的类信息。
sc demo.* 模糊搜索demo包下所有类
sc -d demo.MathGame 打印demo.MathGame的详细信息
profiler start 启动采集(默认是CPU)
profiler getSamples 查看采样的数量
profiler status 查看采样的状态(是否在运行,运行了多久)
profiler stop 停止并生成火焰图
x轴代表采样总量(也就是此刻所有执行的耗时cpu的方法)。
这是注意的是x 轴并不代表时间,而是所有的调用方法合并后,按字母顺序排列。
Y轴代表方法的调用栈深度,每一层都是一个方法。顶部是正在执行的方法。当然调用栈越深,火焰就越高。
鼠标可以点击的选中的每个框就代表了一个栈里的函数,其宽度可以直接理解为CPU时间占比(其实是采样的数量以及与采样总量的占比)。
那么,也就是说占比比较宽的框就表示:
另外火焰图
绿色部分代表Java代码;
黄色部分代表JVM C++代码;
橙色部分代表内核态C语言代码;
红色代表用户态C语言代码;
由此可知,火焰图可以直观的帮我们分析CPU占用情况。
我用的Docker需要把容器里面的html文件复制到Linux。
docker cp fcf3c7aed879:/arthas-output/20231105-161622.html /home/arthas
Linux文件传输到本地
用nc
命令
服务端
nc -l 10078 < 20231105-161622.html
本地
nc 10.100.28.108 10077 > 20231105-161622.html
Github: https://github.com/alibaba/arthas
文档:https://arthas.aliyun.com/doc/
Arthas功能庞大,是线上排查问题,性能分析的利器,建议大家使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。