work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Arthas实践

Posted on 2021-10-24 21:26  work hard work smart  阅读(159)  评论(0编辑  收藏  举报

1、下载

wget https://alibaba.github.io/arthas/arthas-boot.jar

启动 java -jar arthas-boot.jar

 

2、相关命令

1)输入dashboard,仪表盘显示当前进程相关信息

ID 线程ID

NAME 线程名称

GROUP 线程组

 

说明

ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
NAME: 线程名
GROUP: 线程组名
PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
STATE: 线程的状态
CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
TIME: 线程运行总时间,数据格式为分:秒
INTERRUPTED: 线程当前的中断位状态
DAEMON: 是否是daemon线程

通过上述信息,可以帮助我们快速定位相关问题线程。

 

 

2) 查看具体线程信息 thread 线程id

3) 查看类里某个方法的返回值和入参

测试代码:

public class Demo1 {
    public static void main(String[] args) {
        System.out.println("currentThreadName=" + Thread.currentThread().getName());
        demo1();
    }

    private static void demo1(){
        int i = 0;
        while (true){
            i++;
            String result = sayHello("nick" + i);
            try {
                Thread.sleep(1000);
            }catch (Exception e){

            }
        }
    }

    private static String sayHello(String name){
        System.out.println("hello, " + name);
        return "return:" + name;
    }
}

  

命令+类完全限定名+监测方法+表达式

watch com.example.Demo1 sayHello "{params,returnObj}"

表达式核心变量列表:
loader      本次调用类所在的 ClassLoader
clazz       本次调用类的 Class 引用
method      本次调用方法反射引用
target      本次调用类的实例
params      本次调用参数列表,这是一个数组,如果方法是无参方法则为空数组
returnObj   本次调用返回的对象。当且仅当 isReturn==true 成立时候有效,表明方法调用是以正常返回的方式结束。如果当前方法无返回值 void,则值为 null
throwExp    本次调用抛出的异常。当且仅当 isThrow==true 成立时有效,表明方法调用是以抛出异常的方式结束。
isBefore    辅助判断标记,当前的通知节点有可能是在方法一开始就通知,此时 isBefore==true 成立,同时 isThrow==false 和 isReturn==false,因为在方法刚开始时,还无法确定方法调用将会如何结束。
isThrow     辅助判断标记,当前的方法调用以抛异常的形式结束。
isReturn    辅助判断标记,当前的方法调用以正常返回的形式结束。

  

watch 查询异常参数

package com.example.arthasdemo2;

@Service
@Slf4j
public class ArthasTestService {


    public String say(String name){
        if("null".equals(name)){
            throw new RuntimeException("name is null string");
        }
        return  "hello," + name;
    }
} 

Controller层代码

    @GetMapping("/say")
    @ResponseBody
    public String say(@RequestParam String name){
       return   arthasTestService.say(name);
    }

执行如下命令

watch com.example.arthasdemo2.ArthasTestService say "params" -x 2 -e -n 1

然后调用接口

http://localhost:8080/say?name=null

 

 当参数为null时,抛出异常。

 

 

 

 

4)方法调用路径、耗时解析

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

trace com.example.Demo1 sayHello

 

 

5) 时空隧道

方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

tt -t  com.example.Demo1 demo1

 

查看抛出的异常

@Service
@Slf4j
public class ArthasTestService {

    public void demo2_2(){
        log.info("demo2_2");
        throw  new RuntimeException("demo2_2 error");
    }

}

 

tt -t com.example.arthasdemo2.ArthasTestService demo2_2  -n 1

 

 tt  -i 1000

 

6) 查看JVM已加载的类信息

sc -d com.example.Demo1

-d 输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。
如果一个类被多个ClassLoader所加载,则会出现多次

 

7) 退出arthas

quit 退出当前Arthas客户端,其他Arthas客户端不受影响

shutdown  关闭Arthas服务端,所有Arthas客户端全部退出 & 重置所有增强过的类,就不用单独调用reset

 

3、arthas还提供了Web Console

java -jar arthas-boot.jar   --target-ip 192.168.22.89

访问http://192.168.22.89:8563

本机访问

 

4、jad/mc/redefine 热更新

jad   com.exmaple.XXX

com.exmaple是包名

XXX是java类名

查看反编译的源码

创建类LogUtil 

package com.example.arthasdemo2;

import lombok.extern.slf4j.Slf4j;


@Slf4j
public class LogUtil {

    public static void log(String name){
        log.debug("hello," + name);
    }
}

 

Controller层调用该方法

    @GetMapping("/logLevel")
    @ResponseBody
    public String logLevel(@RequestParam String name){
        LogUtil.log(name);
        return "ok";
    } 

调用接口http://localhost:8080/logLevel?name=zhangsan,可以看到没有打印debug日志。

 

查看反编译的源码 jad com.example.arthasdemo2.LogUtil

 

jad反编译LogUtil代码,保存到 /tmp/LogUtil.java

jad --source-only  com.example.arthasdemo2.LogUtil > /tmp/LogUtil.java

 

 

 

 

 利用sc命令搜索jvm已经加载的LogUtil信息

 

 

 

修改/tmp/LogUtil.java的代码利用mc重新编译成class文件

 

 

 

 

 redefine热更新代码

 redefine E:/tmp/com/example/arthasdemo2/LogUtil.class

 

 

 

调用接口http://localhost:8080/logLevel?name=zhangsan,可以发现已经有打印

 

 

 

 5、生成hprof文件

heapdump

 

6、查看线程阻塞问题

Controller层代码

    @GetMapping("/synchronizedMethodTest1")
    @ResponseBody
    public String synchronizedMethod1(){
          arthasTestService.synchronizedMethod();
          return "ok1";
    }


    @GetMapping("/synchronizedMethodTest2")
    @ResponseBody
    public String synchronizedMethod2(){
        arthasTestService.synchronizedMethod();
        return "ok2";
    }

  

Service层代码

    public synchronized  void synchronizedMethod(){
        log.info("synchronizedMethod");
        try {
            //休眠5分钟
            Thread.sleep(300 * 1000);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

  

分别调用

http://localhost:8080/synchronizedMethodTest1

http://localhost:8080/synchronizedMethodTest2

 

然后执行thread -b

 

 可以看出http-nio-8080-exec-2线程阻塞了

- locked com.example.arthasdemo2.ArthasTestService@6845c942 <---- but blocks 1 other threads!

 

参考: 官网地址 https://arthas.aliyun.com/doc/