datax(七)源码阅读之运行时监控MXBean

2022-07-25,,,,

目录

 

一、JMX前置知识

二、datax的运行监控

三、运行时常用的MXBean大全


一、JMX前置知识

官方文档:https://docs.oracle.com/javase/tutorial/jmx/index.html

网上比较不错的文章:http://www.tianshouzhi.com/api/tutorials/jmx/28

简单的说就是,JMX可以通过MBean的注册来实现运行时监控,而MXBean是一种可以支持复杂变量类型的MBean,具体的细节大家可以参考下上面两篇文章

注:一般我们自己在开发springboot项目去实现自定义的监控指标的时候,不会直接去使用jmx,而是更倾向于使用流行的监控框架去实现,比如micrometer + promethues + grafana (micrometer可以用来收集应用的指标,可以是应用的自定义指标或JMX的指标;而promethues作为中心化的指标大盘可以对接各个应用的监控指标,并提供监控告警和对指标进行sql查询的能力;grafana则是对接promethues提供了可视化的能力)

 

二、datax的运行时监控

datax有个VMInfo类,用来运行时获取jvm的各种指标信息并进行打印,包括操作系统相关信息、垃圾收集器相关信息、jvm内存区域相关信息

VMInfo在datax源码中主要有三个场景进行使用(代码中省略了其他杂七杂八的业务逻辑)

1、datax Exgine调用start方法前

VMInfo vmInfo = VMInfo.getVmInfo();
if (vmInfo != null) {
  LOG.info(vmInfo.toString());
}

2、整个job结束之后

VMInfo vmInfo = VMInfo.getVmInfo();
if (vmInfo != null) {
  vmInfo.getDelta(false);
  LOG.info(vmInfo.totalString());
}

3、jobScheduler运行过程中每个汇报周期调用一次进行汇报

VMInfo vmInfo = VMInfo.getVmInfo();
if (vmInfo != null) {
  vmInfo.getDelta(true);
}

可以看到对应的调用姿势也不一样,我们的主要关注点也聚焦到第一个场景,第一个常见打印出来的日志如下:

我们不关注里面的指标数据到底有没有问题,我们就关注下整个执行逻辑。

首先看到getVMInfo这个方法。

private static VMInfo vmInfo;

     /**
     * @return null or vmInfo. null is something error, job no care it.
     */
    public static VMInfo getVmInfo() {
        if (vmInfo == null) {
            synchronized (lock) {
                if (vmInfo == null) {
                    try {
                        vmInfo = new VMInfo();
                    } catch (Exception e) {
                        LOG.warn("no need care, the fail is ignored : vmInfo init failed " + e.getMessage(), e);
                    }
                }
            }

        }
        return vmInfo;
    }

可以看到就是一个简单的单例来进行VMInfo对象的实例化

 

再看到VMInfo的构造方法::

private VMInfo() {
        //初始化静态信息
        osMXBean = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
        runtimeMXBean = java.lang.management.ManagementFactory.getRuntimeMXBean();
        garbageCollectorMXBeanList = java.lang.management.ManagementFactory.getGarbageCollectorMXBeans();
        memoryPoolMXBeanList = java.lang.management.ManagementFactory.getMemoryPoolMXBeans();

        osInfo = runtimeMXBean.getVmVendor() + " " + runtimeMXBean.getSpecVersion() + " " + runtimeMXBean.getVmVersion();
        jvmInfo = osMXBean.getName() + " " + osMXBean.getArch() + " " + osMXBean.getVersion();
        totalProcessorCount = osMXBean.getAvailableProcessors();

        //构建startPhyOSStatus
        startPhyOSStatus = new PhyOSStatus();
        LOG.info("VMInfo# operatingSystem class => " + osMXBean.getClass().getName());
        if (VMInfo.isSunOsMBean(osMXBean)) {
            {
                startPhyOSStatus.totalPhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getTotalPhysicalMemorySize");
                startPhyOSStatus.freePhysicalMemory = VMInfo.getLongFromOperatingSystem(osMXBean, "getFreePhysicalMemorySize");
                startPhyOSStatus.maxFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getMaxFileDescriptorCount");
                startPhyOSStatus.currentOpenFileDescriptorCount = VMInfo.getLongFromOperatingSystem(osMXBean, "getOpenFileDescriptorCount");
            }
        }

        //初始化processGCStatus;
        for (GarbageCollectorMXBean garbage : garbageCollectorMXBeanList) {
            GCStatus gcStatus = new GCStatus();
            gcStatus.name = garbage.getName();
            processGCStatus.gcStatusMap.put(garbage.getName(), gcStatus);
        }

        //初始化processMemoryStatus
        if (memoryPoolMXBeanList != null && !memoryPoolMXBeanList.isEmpty()) {
            for (MemoryPoolMXBean pool : memoryPoolMXBeanList) {
                MemoryStatus memoryStatus = new MemoryStatus();
                memoryStatus.name = pool.getName();
                memoryStatus.initSize = pool.getUsage().getInit();
                memoryStatus.maxSize = pool.getUsage().getMax();
                processMomoryStatus.memoryStatusMap.put(pool.getName(), memoryStatus);
            }
        }
    }

vmInfo.toString()方法:

public String toString() {
        return "the machine info  => \n\n"
                + "\tosInfo:\t" + osInfo + "\n"
                + "\tjvmInfo:\t" + jvmInfo + "\n"
                + "\tcpu num:\t" + totalProcessorCount + "\n\n"
                + startPhyOSStatus.toString() + "\n"
                + processGCStatus.toString() + "\n"
                + processMomoryStatus.toString() + "\n";
    }

大体的逻辑就是使用下列的MXBean获取信息:

1、OperatingSystemMXBean获取操作系统相关信息,主要获取了操作系统名称、操作系统的架构、操作系统的版本。如果是unix操作系统的话,也进行总物理内存、已释放的物理内存、最大文件描述符以及已经打开的文件描述符

2、RuntimeMXBean获取java虚拟机相关信息,主要获取了Java 虚拟机实现供应商、Java 虚拟机规范版本、Java 虚拟机实现版本

3、GarbageCollectorMXBean列表获取垃圾收集器相关信息,主要获取了垃圾收集器的名称

4、MemoryPoolMXBean获取jvm内存区域列表相关信息,主要获取了每个内存空间的名称、初始空间以及最大空间。

 

 

三、运行时常用的MXBean大全

参考文档(主要是java.lang.management包下):https://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/management/package-use.html

本文地址:https://blog.csdn.net/qq_31957747/article/details/112097501

《datax(七)源码阅读之运行时监控MXBean.doc》

下载本文的Word格式文档,以方便收藏与打印。