Arthas使用及常用命令

本文详细介绍了如何使用Arthas进行线上问题排查,包括Arthas的下载、启动,以及dashboard、thread、watch、trace等常用命令的使用,通过实例展示了如何解决CPU飙升、死锁等问题,是Java开发者排查问题的实用指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:本文介绍线上问题排查利器,Arthas的使用及常用命令;

创建项目

首先,创建一个Demo项目,该项目有以下三个接口,对应三个问题:

  • test1:会造成CPU飙升,接近100%;

  • test2:会造成死锁;

  • test3:输出一段有错误拼写的信息;

(Controller代码)

    @Autowired
    private ArthasService arthasService;

    /**
     * 模拟CPU飙升
     *
     * @return
     */
    @GetMapping({"/test1"})
    public String test1() {
        arthasService.cpuHigh();
        return "cpuHigh";
    }

    /**
     * 死锁问题
     *
     * @return
     */
    @GetMapping({"/test2"})
    public String test2() {
        arthasService.deadThread();
        return "deadThread";
    }

    /**
     * 模拟热更新
     *
     * @return
     */
    @GetMapping({"/test3"})
    public String test3() {
        return arthasService.updateOut();
    }

(ServiceImpl代码)

import org.springframework.stereotype.Service;

@Service
public class ArthasService {

    /**
     * 模拟CPU飙升
     */
    public void cpuHigh() {
        new Thread(() -> {
            while (true) {}
        }).start();
    }

    /**
     * 死锁问题
     */
    public void deadThread() {
        Object resourceA = new Object();
        Object resourceB = new Object();
        Thread threadA = new Thread(() -> {
            synchronized (resourceA) {
                System.out.println(Thread.currentThread() + " get ResourceA");
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resourceB");
                synchronized (resourceB) {
                    System.out.println(Thread.currentThread() + " get resourceB");
                }
            }
        });
        Thread threadB = new Thread(() -> {
            synchronized (resourceB) {
                System.out.println(Thread.currentThread() + " get ResourceB");
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resourceA");
                synchronized (resourceA) {
                    System.out.println(Thread.currentThread() + " get resourceA");
                }
            }
        });
        threadA.start();
        threadB.start();
    }

    /**
     * 模拟热更新
     *
     * @return
     */
    public String updateOut() {
        String name = "Helloo Arthas!";
        return name;
    }
}

将该Demo打成jar包,放到服务器上运行:

nohup java -jar arthas-demo.jar > output.log &

在这里插入图片描述

浏览器访问,没得问题

在这里插入图片描述

通过top命令可以查看到该程序占用CPU资源很高;

在这里插入图片描述

Arthas下载和启动

这时,可通过Arthas工具对上面的项目进行问题排查,使用如下:

(1)下载

Arthas官网(https://arthas.aliyun.com/),在服务器上敲下面的命令将arthas的jar包下载下来

curl -O https://arthas.aliyun.com/math-game.jar

可以在当前目录下看到 arthas-boot.jar 文件

在这里插入图片描述

(2)启动

通过java命令启动Arthas

java -jar arthas-boot.jar

在这里插入图片描述

它会检测到当前正在运行的java项目,并罗列出来,可敲前面的序号针对某个项目使用Arthas,如上图,我只有一个,敲1即可,这样就进入了Arthas的操作命令行。

在这里插入图片描述

接下来,就可以针对我们前面启动的项目进行一系列操作。

Arthas常用命令

dashboard

说明:查看当前系统的实时数据面板,默认每5秒刷新一次。

可配合的参数有:

  • -i:刷新实时数据的时间间隔(ms),默认5000ms;

  • -n:刷新实时数据的次数;

在这里插入图片描述

thread

说明:查看当前线程信息,查看线程的堆栈。

可配合的参数有:

  • id:线程ID,dashboard上面一栏的第一列数值;

  • -b:找出当前阻塞其他线程的线程;

排查问题一

通过以上两个命令,我们可以排查出前面项目中的CPU飙升和死锁的问题,如下:

敲入dashboard命令后,浏览器访问/test1接口

在这里插入图片描述

观察数据面板,发现有一个线程CPU占用率极高;

在这里插入图片描述

Ctrl + C停止数据面板,敲thread 进程id,查看该线程信息;

在这里插入图片描述

该类的第13行代码导致CPU飙升,此时可以进入IDEA中排查问题。

在这里插入图片描述

注释掉这段死循环代码,重新打包上传;

排查问题二

问题二是死锁问题,同样的,先敲dashboard调出数据面板,然后访问/test2接口,观察数据变化;

在这里插入图片描述

可以看到,存在BLOCKED已阻塞的线程;

在这里插入图片描述

使用thread id命令查看该线程信息,也可使用thread -b查看阻塞线程的信息;

在这里插入图片描述

可查到造成阻塞线程的代码位置;

watch

说明:函数执行数据观测,使用该命令可以观测方法相关情况,如方法的参数、返回值、异常信息等;

配合该命令的相关参数如下:

在这里插入图片描述

如下,观测该类中的cpuHigh()方法,深度为2;

watch com.example.arthasdemo.service.ArthasService cpuHigh -x 2

在这里插入图片描述

接着去浏览器上访问对应的接口,会打印如下信息:

在这里插入图片描述

有调用的类、方法数量及用时,返回值等信息;

此时,修改一下项目代码,在第三个接口前面手动制造一个异常,如下:

    /**
     * 模拟热更新
     *
     * @return
     */
    public String updateOut() {
        // 手动制造一个异常
        System.out.println(1/0);
        String name = "Helloo Arthas!";
        return name;
    }

重新打包,上传到服务器上运行,敲下面的命令可观察对应方法抛出的异常信息;

watch com.example.arthasdemo.service.ArthasService updateOut '{throwExp}' -e -x 2

在这里插入图片描述

浏览器上访问对应的接口,观察Arthas打印的信息:

在这里插入图片描述

打印了异常信息,该命令可用于线上项目的BUG排查;

在这里插入图片描述

trace

说明:可打印方法内部调用路径,并输出方法路径上的每个节点上耗时;

如下,打印/test1接口的信息:

trace com.example.arthasdemo.controller.TestController test1

浏览器访问test1接口,该命令会打印出该接口的调用路径,以及各个节点的耗时,该命令可用于接口优化;

在这里插入图片描述

另外,配合#cost参数可找出在对应耗时范围内的节点,如下,找出耗时在0.1ms以上的节点;

在这里插入图片描述

jad

说明:反编译指定已加载类的源码;

项目打成jar后都是class文件,通过该命令可将线上项目的class文件反编译为java文件。如下,将对应的类反编译为java文件,箭头右侧是反编译后的文件路径及文件名:

jad com.example.arthasdemo.service.ArthasService > /home/ArthasService.java

可使用cat命令打开该文件,可以查看反编译后的源码文件,但文件中除了源码还有一些类加载器信息和附带的代码行数,是不能编译通过的

在这里插入图片描述

可在反编译时加上这两个参数,--source-only--lineNumber false 得到纯净的源码。前者表示只要源码,后者表示不加行号。

在这里插入图片描述

sc

说明:查看 JVM 已加载的类信息,-d可输出当前类的详细信息;

如下,查看某类的详细信息:

sc -d com.example.arthasdemo.service.ArthasService

注意最后一行信息,类加载器的Hash值,后面指定编译器编译某类的java文件时可用到;

在这里插入图片描述

mc

说明:编译.java文件生成.class;

配合的参数如下:

  • -c:指定类加载器,可使用前的sc命令查看;

  • -d:编译后的目录;

将前面反编译的java文件,再编译成class文件,如下:

mc -c 1593948d /home/ArthasService.java -d /home

class文件直接打开无法识别,可在对应的目录下找到该class文件;

在这里插入图片描述

redefine

说明:加载外部的.class文件;

如下,加载前面mc命令产生的class文件:

redefine /home/com/example/arthasdemo/service/ArthasService.class 

-c可指定类加载器,和前面的mc一样;

在这里插入图片描述

排查问题三

jad命令mc命令redefine命令配合使用,可实现线上项目热更新,对/test3接口打印的错误英文信息进行临时修复。

在这里插入图片描述

首先,使用jad命令反编译对应的类,然后使用vim命令修改源码,或者下载到本地使用编辑工具修改;

修改内容:Helloo Arthas! ⇒ Hello Arthas!

在这里插入图片描述

其次,使用sc命令mc命令编译修改后的java文件,成class文件;

在这里插入图片描述

最后,使用redefine命令加载修改源码后的class文件,实现在线更新;

在这里插入图片描述

此时,再访问/test3接口,打印的信息变成了我们修改后的内容;

在这里插入图片描述

但是,redefine命令有限制条件,有的修改内容即使加载也不会生效,官方文档说明如下:

在这里插入图片描述

其他命令

除了上面一些功能命令,还有一些其他辅助命令,如下:

  • cat:查看文件;

  • cls:清屏;

  • stop:关闭 Arthas 服务端;

  • exit:退出当前 Arthas 客户端,其他 Arthas 客户端不受影响。;

  • history:打印命令历史

总结

本文介绍了Arthas的使用及一些常用方法,更丰富的命令及使用,强烈建议大家去官网中阅读文档(https://arthas.aliyun.com/doc/

### Arthas 调试命令列表 #### 查看源码 通过 `jad` 命令可以反编译并查看指定类的方法源码,这对于理解现有代码逻辑非常有帮助[^1]。 ```bash jad com.example.MyClass ``` #### 清屏 为了保持终端界面整洁,可使用 `cls` 来清除屏幕上的所有内容。 ```bash cls ``` #### 获取静态字段信息 利用 `getstatic` 可以获取某个特定对象实例的静态变量值,这有助于监控全局状态的变化情况。 ```bash getstatic java.lang.System out ``` #### 方法执行监视 - **Watch**: 使用 `watch` 命令来观察目标函数每次被调用时传入参数以及最终返回的结果。此功能对于追踪数据流特别有用。 ```bash watch com.example.MyService 'request()' '{params, returnObj}' ``` - **Trace**: 对于想要了解某段代码运行期间消耗了多少时间的情况,则应该采用 `trace` 。它不仅能够统计整个过程所花费的时间,还能进一步细分到各个子操作层面去分析性能瓶颈所在之处。 ```bash trace com.example.MyController handleRequest ``` #### 类加载器查询 当遇到类找不到或者版本冲突等问题时,可以通过 `sc` (search class) 加上 `-d` 参数配合管道符过滤出具体的 ClassLoader Hash ,从而定位问题根源所在[^2]。 ```bash sc -d org.springframework.web.servlet.DispatcherServlet | grep classLoaderHash ``` #### 动态修改业务逻辑 如果需要在线调整某些行为而无需重启应用服务器的话,那么就可以考虑先将字节码转换成 Java 文件再做相应改动;之后借助内存中的即时编译机制重新生成新的 .class 文件实现热部署效果。 另外还可以运用 OGNL 表达式直接对应用程序内的任意属性进行读写访问,例如向集合中添加新元素等简单变更操作也变得轻而易举了[^3]: ```bash ognl '@java.util.Collections@singletonList("new item")' ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何中应

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值