前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Arthas】实战教程

【Arthas】实战教程

原创
作者头像
后端码匠
修改于 2023-11-06 02:06:51
修改于 2023-11-06 02:06:51
6810
举报
文章被收录于专栏:后端码匠后端码匠

【Arthas】实战教程

前言

最近团队在研究线上问题排查方式,发现线上存在CPU飙升问题,测试环境无法复现,查阅资料发现 Arthas 能够分析此类问题。

排查利器

Arthas,开源的Java诊断工具。

功能

那么Arthas能帮我们做什么事情呢?详细的用法大家可以查官方文档,这里带大家实践。

代码语言:shell
AI代码解释
复制
可以监控到JVM的实时的运行状态;
可以实时查看系统的运行状况;
遇到线上高流量系统,没有打日志,同时不能debug,线下却又不能重现,可以无须重启在线查看类方法输入输出,如同日志一般;
怀疑代码没有commit就发布了,它帮你在线查看;
......

安装启动

这里推荐快速简单的安装方法,大家也可下载包安装。

代码语言:shell
AI代码解释
复制
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 文件如下

代码语言:shell
AI代码解释
复制
...

# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas

...

如果你用的是JRE那么用的时候,肯定会有 tool.jar找不见的异常。

所以在打镜像的时候需要选择jdk,具体可以看官方文档。

代码语言:shell
AI代码解释
复制
https://arthas.aliyun.com/doc/docker.html

我所做的项目用了自己的基础镜像,暂时无法在打镜像的时候引入JDK,这就需要特殊处理下,步骤如下:

1、在Linx本地JDK目录如下

代码语言:shell
AI代码解释
复制
[root@master jdk1.8.0_221]# pwd
/home/jdk1.8.0_221

2、找到运行的容器

代码语言:shell
AI代码解释
复制
[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复制到容器中

代码语言:shell
AI代码解释
复制
docker cp jdk1.8.0_221/ de37f7e97560:/opt/java

然后就可以进入容器启动Arthas。

代码语言:shell
AI代码解释
复制
[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。

代码语言:shell
AI代码解释
复制
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

星号代表选中的进程。

代码语言:shell
AI代码解释
复制
[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]$ 

系统dashboard

可以查看系统的整体情况如下图:线程、内存、系统运行时信息等

JVM全景报表

帮助你分析现有系统情况,类加载情况,线程情况,系统内存情况等等如下图:并未截取全部。

thread 命令

代码语言:shell
AI代码解释
复制
thread 查看当前线程
thread id 查看指定线程id 的堆栈
thread -n 2 查看cpu最忙的前2个线程
thread -b, 找出当前阻塞其他线程的线程
thread -n 2 -i 1000 列出1000ms内最忙的2个线程堆栈

thread -b,找出当前阻塞其他线程的线程。

有时候发现服务卡住了, 一般情况是:

某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成阻塞。这个命令可以解决。

watch命令,执行数据监测

线上没有打日志,同时不能debug,线下却又不能重现,watch命令可以无须重启在线查看类方法输入输出,如同日志一般。

能观察到的方法监测的数据范围:返回值、抛出异常、入参。

代码语言:shell
AI代码解释
复制
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

jad命令,反编译指定已加载类的源码

你有时候有这样的疑惑,现在运行的代码是我提交的代码吗?虽然master有,但是线上运行的包是这个master打的吗?它可以直接在线反编译。

代码语言:shell
AI代码解释
复制
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命令

跟踪方法内部调用路径,并输出方法路径上的每个节点上耗时。

代码语言:shell
AI代码解释
复制
trace demo.MathGame run 追踪demo.MathGame run 方法
trace demo.MathGame run -n 1  追踪demo.MathGame run 方法只1次即退出
trace demo.MathGame run '#cost > 10' 追踪大于10ms的
代码语言:shell
AI代码解释
复制
[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

sc 命令

查看JVM已加载的类信息。

代码语言:shell
AI代码解释
复制
sc demo.*  模糊搜索demo包下所有类
sc -d demo.MathGame 打印demo.MathGame的详细信息

火焰图生成

代码语言:shell
AI代码解释
复制
profiler start 启动采集(默认是CPU)
profiler getSamples 查看采样的数量
profiler status  查看采样的状态(是否在运行,运行了多久)
profiler stop 停止并生成火焰图

x轴代表采样总量(也就是此刻所有执行的耗时cpu的方法)。

这是注意的是x 轴并不代表时间,而是所有的调用方法合并后,按字母顺序排列。

Y轴代表方法的调用栈深度,每一层都是一个方法。顶部是正在执行的方法。当然调用栈越深,火焰就越高。

鼠标可以点击的选中的每个框就代表了一个栈里的函数,其宽度可以直接理解为CPU时间占比(其实是采样的数量以及与采样总量的占比)。

那么,也就是说占比比较宽的框就表示:

  • 该函数运行时间较长(单次时间长)
  • 被调用次数较多.(调用频率高) 进而被采样的次数比较多,占用的CPU时间多。

另外火焰图

绿色部分代表Java代码;

黄色部分代表JVM C++代码;

橙色部分代表内核态C语言代码;

红色代表用户态C语言代码;

由此可知,火焰图可以直观的帮我们分析CPU占用情况。

我用的Docker需要把容器里面的html文件复制到Linux

代码语言:shell
AI代码解释
复制
docker cp fcf3c7aed879:/arthas-output/20231105-161622.html /home/arthas

Linux文件传输到本地

nc命令

服务端

代码语言:shell
AI代码解释
复制
nc -l 10078 < 20231105-161622.html

本地

代码语言:shell
AI代码解释
复制
nc 10.100.28.108 10077 > 20231105-161622.html

官方文档

Github: https://github.com/alibaba/arthas

文档:https://arthas.aliyun.com/doc/

总结

Arthas功能庞大,是线上排查问题,性能分析的利器,建议大家使用。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
java安装以及快速入门java基本语句
Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
长生不死大王
2025/04/28
2260
Java基础
关键字:Java中的关键字是对编译器有特殊意义的词。比如class是用来定义类的关键字,编译器遇到class就知道这是定义了一个类
Breeze.
2022/09/16
1.2K0
Java基础
JAVA学习笔记_入门基础
JAVA学习笔记_入门基础1. 符号及类型1.1 添加注释comment1.2 关键字keywords1.3 标识符1.4 常量1.5 变量和数据类型1.6 数据类型的转换1.7 ASCII编码表
用户7886150
2020/12/04
5120
Java的一些基础知识总结
常量(Constant):初始化(initialize)后不能再改变值!不会变动的值。
白衣少年
2022/12/26
7440
Java的一些基础知识总结
JAVA基础知识总结
学习视频【狂神说Java】Java零基础学习视频通俗易懂_哔哩哔哩 (゜-゜)つロ 干杯~-bilibil
半生瓜的blog
2023/05/12
8470
JAVA基础知识总结
JAVA基础复习day-01
byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
阮键
2019/08/07
6420
Java笔记(上)
计算机编程语言的发展,是随着计算机本身硬件发展而发展的。硬件速度越快、体积越小、成本越低,应用到人类社会的场景就会越多,那么所需要的算法就会越复杂,也就要求计算机编程语言越高级。最初重达几十吨但一秒只能运算5000次的ENIAC(世界上第一台计算机),只能做非常小的应用,比如:某些情况的弹道计算。现在任何一个人的手机运算能力都可以秒杀那个年代地球上所有计算机运算能力的总和。计算机编程语言的发展历经了从低级到高级发展。发展的核心思想就是“让人更容易编程”。越容易使用的语言,就有越多人使用;越多人使用,就有越多协作;越多协作,就可以创造越复杂的物体;计算机语言经历了三代:第一代是机器语言,第二代是汇编语言,第三代是高级语言。
星辰xc
2022/04/09
8030
Java笔记(上)
小闫陪你入门 Java (三)
First say to yourself what you would be; and then do what you have to do.
小闫同学啊
2019/09/24
5440
Java 零基础入门学习(小白也能看懂!)
不仅如此,Java还是一个有一系列计算机软件和规范形成的技术体系,这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境,并广泛应用于嵌入式系统、移动终端、企业服务器、大型机等各种场合。
爱敲代码的小杨.
2024/05/07
3440
Java 零基础入门学习(小白也能看懂!)
Java学习之基础语法篇
说到java不得不提的是java的类加载机制,java是一个依赖于jvm(也就是java的虚拟机)实现跨平台的一个开发语言,java所有的代码都会在jvm里面运行,java在运行中xx.java的源文件会被编译成class后缀文件(字节码文件)才能运行。java类初始化的时候调用java.lang.ClassLoader加载字节码文件。 下面来看一下jdk和jre、jvm的关系示意图。
全栈程序员站长
2021/12/13
5680
Java学习之基础语法篇
Java——基础语法(一)
在Java中,变量需要先声明再使用,声明方式为"数据类型 变量名"。Java有八种基本数据类型:byte、short、int、long、float、double、char、boolean。除了基本类型,Java还支持引用类型,如字符串和数组。 下面我将更详细地介绍Java中的变量。
一只
2024/07/05
1570
Java第一次月考50题及解析
1、【单选题】在Java中,用()关键字修饰的方法可以直接通过类名来调用。 A.static B.final C.public D.void 【正确答案】A
海拥
2021/08/23
1.6K0
java 程序设计题库
A、System.out.println(“I am Java Expert”);
全栈程序员站长
2022/06/25
1.7K0
优秀的后端应该知道的易错点
TIOBE 编程社区给出了 2024 年编程语言流行度的指标,南哥看到我们的 Java 现在是排第三~
JavaSouth南哥
2024/12/12
1370
优秀的后端应该知道的易错点
Java每日一练(2017/8/17)
每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?__biz=MzA5MTMyNTI0Nw=
Java学习
2018/04/18
6220
Java每日一练(2017/8/17)
Java 中文官方教程 2022 版(二)
现在你已经学会了如何声明和初始化变量,你可能想知道如何对其进行操作。学习 Java 编程语言的运算符是一个很好的开始。运算符是执行特定操作的特殊符号,作用于一个、两个或三个操作数,然后返回一个结果。
ApacheCN_飞龙
2024/05/24
2980
【Java零基础入门篇】第 ② 期 - Java语言基础(四)
这三种不同的结构有一个共同点,就是它们都只有一个入口,也只有一个出口。程序中使用了上面这些结构到底有什么好处呢?这些单一入、出口可以让程序易读、好维护,也可以减少调试的时间。
命运之光
2024/03/20
1340
【Java零基础入门篇】第 ② 期 - Java语言基础(四)
JAVA从入门到放弃(2):数据类型及其计算
因为Java是面向对象的语言,一个程序的基本单位就是class,class是关键字,这里定义的class名字就是Hello:
一粒小麦
2020/03/10
1.2K0
JAVA知识总结
下面是一个简单的HelloWorld.java程序,展示了Java程序的基本结构和注释的使用。
lfffffy
2024/12/26
1510
【Java零基础入门篇】第 ② 期 - Java语言基础(三)
Java中的语句有很多种形式,表达式就是其中一种形式。表达式是由操作数与运算符所组成:操作数可以是常量、变量也可以是方法,而运算符就是数学中的运算符号,如“+”、“-”、“*”、“/”、“%”等。以下面的表达式(z+100)为例,“z”与“100”都是操作数,而“+”就是运算符。
命运之光
2024/03/20
1210
【Java零基础入门篇】第 ② 期 - Java语言基础(三)
相关推荐
java安装以及快速入门java基本语句
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档