Java与C++之间有一睹由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
Arthas(阿尔萨斯) 能为你做什么?

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到JVM的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?

1.启动Arthas

https://arthas.aliyun.com/doc/quick-start.html 请看官方到快速入门,下载好Arthas jar包到本地
java 对接 阿里盯盯 阿里java监控_java
入门的第一步下载官方的demo,然后启动,通过jps 获取进程id,在启动Arthas jar包,然后进行诊断

2.使用Arthas

这里自己有一个dmeo例子,用于死锁的代码实例:

@Slf4j
public class ArthasTest {
    private static Logger log = Logger.getLogger("MyLogger");
    private static HashSet hashSet = new HashSet();
    /** 线程池,大小1*/
    private static ExecutorService executorService = Executors.newFixedThreadPool(1);

    public static void main(String[] args) {
        // 模拟 CPU 过高,这里注释掉了,测试时可以打开
        // cpu();
        // 模拟线程阻塞
        thread();
        // 模拟线程死锁
        deadThread();
        // 不断的向 hashSet 集合增加数据
        addHashSetThread();
    }

    /**
     * 不断的向 hashSet 集合添加数据
     */
    public static void addHashSetThread() {
        // 初始化常量
        new Thread(() -> {
            int count = 0;
            while (true) {
                try {
                    hashSet.add("count" + count);
                    Thread.sleep(10000);
                    count++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public static void cpu() {
        cpuHigh();
        cpuNormal();
    }

    /**
     * 极度消耗CPU的线程
     */
    private static void cpuHigh() {
        Thread thread = new Thread(() -> {
            while (true) {
                log.info("cpu start 100");
            }
        });
        // 添加到线程
        executorService.submit(thread);
    }

    /**
     * 普通消耗CPU的线程
     */
    private static void cpuNormal() {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    log.info("cpu start");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    /**
     * 模拟线程阻塞,向已经满了的线程池提交线程
     */
    private static void thread() {
        Thread thread = new Thread(() -> {
            while (true) {
//                log.debug("thread start");
                log.info("thread start");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 添加到线程
        executorService.submit(thread);
    }

    /**
     * 死锁
     */
    private static void deadThread() {
        /** 创建资源 */
        Object resourceA = new Object();
        Object resourceB = new Object();
        // 创建线程
        Thread threadA = new Thread(() -> {
            synchronized (resourceA) {
                log.info(Thread.currentThread() + " get ResourceA");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info(Thread.currentThread() + "waiting get resourceB");
                synchronized (resourceB) {
                    log.info(Thread.currentThread() + " get resourceB");
                }
            }
        });

        Thread threadB = new Thread(() -> {
            synchronized (resourceB) {
                log.info(Thread.currentThread() + " get ResourceB");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info(Thread.currentThread() + "waiting get resourceA");
                synchronized (resourceA) {
                    log.info(Thread.currentThread() + " get resourceA");
                }
            }
        });
        threadA.start();
        threadB.start();
    }
}

java 对接 阿里盯盯 阿里java监控_jvm_02


这里就是启动成功了,我们进入了test的进程id程序中,然后我们就可以使用官方文档上面的命令进行分析,注意这里的命令和linunx中的差不多

3.使用Arthas 命令进行分析

https://arthas.aliyun.com/doc/advanced-use.html 官方文档中,列出了很多的命令,有不同功能的

java 对接 阿里盯盯 阿里java监控_jar包_03

dashboard

当前系统的实时数据面板,按 ctrl+c 退出。
dashboard

java 对接 阿里盯盯 阿里java监控_jar包_04

实时打印出jvm的信息,以及gc的情况

thread

查看当前线程信息,查看线程的堆栈

java 对接 阿里盯盯 阿里java监控_jvm_05


java 对接 阿里盯盯 阿里java监控_java_06


class/classloader相关

sc 查看JVM已加载的类信息

java 对接 阿里盯盯 阿里java监控_java_07

最后推荐大家看看阿里推荐的arthas用户案例分析,看看大家都是这么在项目中去使用 arthas 去处理线上问题的

java 对接 阿里盯盯 阿里java监控_jar包_08


https://github.com/alibaba/arthas/issues/1202

java 对接 阿里盯盯 阿里java监控_jar包_09


可以学习一波经验,好了,一起学习,加油