Java命令行监控工具-线上问题排查

2,448 阅读5分钟

项目部署上线之后,为了确保项目运行是正常的,需要监控应用的各项指标;

公司虽然已经封装好了监控的内容,我们使用对应的工具查看指标就可以了,但是如果有时候真正出现了问题,我们可能还是要到原始机器上进行操作查看。

而基础的命令行工具肯定是必须要掌握的;

以下介绍常用的命令行工具:

arthas - 需安装

这是阿里开源的一款好用的jvm监控工具,可以看做是把JDK中常用的工具都封装起来,并且又增加了许多新的gonna特性;

安装使用:

# 安装方式一,参考地址:https://alibaba.github.io/arthas/install-detail.html
curl -L https://alibaba.github.io/arthas/install.sh | sh
# 安装方式二
java -jar arthas-boot.jar --repo-mirror aliyun --use-http

# 使用
java -jar arthas-boot.jar

注意:使用完之后记得shutdown,如果不shutdown可能存在一些问题,比如监控的仍然是上次的jvm进程;

一些基于Arthas的排查方法:

github.com/alibaba/art…

img

# 查看入参和返回值
watch 类名 方法名 "{params,returnObj}" -x 2

# 查看某个方法参数对象的属性
watch com.taobao.container.web.arthas.rest.MyAppsController myFavoriteApps 'target.myFavAppsMapper'

# 查看某个类的静态属性
getstatic com.xxx.CommonDiamondConfig ruleConditionComposeMap

JDK - 自带

jps - 查看系统中运行的Java线程数

我理解这个应该是Java中最常用的命令行工具了,无论何时想排查问题,都会使用这个命令:

  • 查看还有没有存活的Java进程
  • 查看存活的Java进程运行参数

image.png

jps -m 查看jvm进程并且带有参数查看 jps -v 查看传递到jvm的参数

官方jps解释:docs.oracle.com/javase/7/do…

jstat - 统计JVM信息

显示JVM的性能统计信息, 常见用法:jstat - [-t] [-h] [ []] 例如:查看某个JVM进程的垃圾回收信息:

#                 指定进程  指定间隔   指定次数
jstat -gcutil -t  6533  1000 5

image.png

其中-gc查看垃圾收集器中的信息, 主要包含jvm的运行时数据区统计。

  • -gcold 查看老年代垃圾回收信息
  • -gcutil 垃圾回收的总结信息

后缀为C的代表当前区的容量,后缀为U的代表已经使用了多少容量,后缀为T的代表耗时

S0C 存活区0的容量(KB) S1C 存活区1的容量(KB) S0U 存活区0使用的空间 (KB). S1U 存活区1的利用空间 (KB). EC Eden区的容量(KB). EU Eden区利用的容量(KB). OC 老年代容量(KB). OU 老年代使用容量(KB). PC 当前永久带的容量(KB). PU 永久带使用容量(KB). YGC 发生了多少次Young GC YGCT Young GC的时间 FGC Full GC的次数 FGCT Full GC的收集时间 GCT 总共的GC时间.

官方jstat解释:docs.oracle.com/javase/7/do…

jstack

查看线程堆栈信息:

  • 在发生死锁的时候可以利用这个命令查找死锁或者在发生死循环的时候利用此命令排查。
  • jstack vmpid 会打印线程的堆栈信息。通过堆栈可以查看具体线程正在执行那些代码,

比如排查死锁,死锁代码:

public class DeadLock {

    private static Object o1 = new Object();
    private static Object o2 = new Object();
    private static CountDownLatch countDownLatch = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread(){
            @Override
            public void run() {
                synchronized (o1){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1 获得锁1");
                    synchronized (o2){
                        System.out.println("线程1 获得锁2");
                        countDownLatch.countDown();
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                synchronized (o2){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程2 获得锁2");
                    synchronized (o1){
                        System.out.println("线程2 获得锁1");
                        countDownLatch.countDown();
                    }
                }
            }
        }.start();

        countDownLatch.await();
        System.out.println("执行完毕");
        
    }

}

死锁之后: 可以看到jstack帮我们找到了死锁。

image.png

jstack官方文档解释

jinfo - 查看JVM启动时候设置的参数

jinfo可以查看当前JVM线程配置的系统属性,以及运行时设置的参数值。

直接使用jinfo

  1. 前半段是系统的属性
  2. 后半段是jvm的参数

image.png

image.png

我们也可以直接使用jinfo查看具体的某个参数值:

image.png

jinfo官方解释

jmap分析堆

在发生OME的时候,会用jmap分析堆中具体是什么问题,才能更好的解决问题。jmap一般和mat配合使用。一般在java开发的项目启动时候,最好加上下面命令,在内存溢出的时候可以通过日志查看信息。

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/java/dump

当然在项目运行的时候也可以使用jmap -heap jvmpid查看对象内存的映射。 演示堆内存溢出代码

public class DealCycle {
    public static LinkedList<Integer> linkedList = new LinkedList<>();
    public static void main(String[] args) {
        int i = 0;
        while (true){
            linkedList.add(i);
        }
    }
}

运行会由于OOM会自动创建一个堆文件,如果每次都等到内存溢出才导出文件时间就有些晚了,也可以使用jmap直接导出

img

导出的Hprof文件,可以直接下载下来使用jvisualvm直接分析:

img

其他Jmap常用方法:
打印heap的概要信息,GC使用的算法,heap(堆)的配置及JVM堆内存的使用情况.

jmap -heap pid

打印每个class的实例数目,内存占用,类全名信息,VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.

jmap -histo:live pid

输出jvm的heap内容到文件,live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.

jmap -dump:live,format=b,file=myjmapfile.txt pid

finalizerinfo 打印正等候回收的对象的信息

jmap -finalizerinfo pid

jmap官方解释

总结

1、在项目中监控肯定是必不可少的,但是到真正需要深入问题的时候我们可能还是需要到具体的机器上使用命令行进行分析。

2、集团开源了好用的arthas工具,并且有许多人分享了使用arthas排查问题的经验;

3、JDK内部也提供了许多有用的命令行工具,帮助我们有效的排查问题;