JMX:Java程序监控的基石

  • 一、什么是JMX?
  • 二、JMX架构
    • 1.MBean
      • 1.1 MBean类型
      • 1.2 常用的MBean
      • 1.3 MBean和MXBean的区别
    • 2.MBeanServer
    • 3.适配器和连接器
    • 4.JMX客户端
  • 三、JMX应用场景
    • 1.dashboard监控面板
    • 2.动态修改线上日志级别
    • 3.查看数据库连接池使用情况
    • 4.查看自定义连接池使用情况
    • 5.查看quartz-job任务执行情况
    • 6.通知告警
  • 四、自定义MBean
    • 1.MBean接口方式
    • 2.MXBean接口方式
    • 3.Spring Bean方式
  • 五、参考资料

一、什么是JMX?

JMX (Java Management Extensions)是一个为应用程序植入管理功能的框架 ,从Java 1.5开始引入到标准Java技术平台中。

JMX是Java管理系统的一个标准、规范,开发者可以据此定制开发自己的扩展功能;除了JDK自身实现了的一些扩展功能,第三方类库或中间件也对此进行扩展,比如spring、quartz-job、commons-pool2、tomcat。

JMX主要被用来监测和管理 Java 程序,包括对JVM 内存、CPU 、线程、垃圾收集情况等等。目前市面上的Java监控工具基本都用到了JMX,比如jconsole、jmc、jvisualvm、jprofiler、arthas等。

二、JMX架构

1.MBean

MBean(Managed Bean)即被管理的资源,本质上是一个Bean对象,它包含一些属性和方法,用来获取被管理的资源的状态和操纵资源的行为;JMX 中共有四种类型的 MBean,分别是 Standard MBean, Dynamic MBean, Open MBean, Model MBean。JDK 提供的 MBean 主要在 java.lang.management 和 javax.management包里面。

1.1 MBean类型

类型 描述
Standard MBean 这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,然后MBean必须实现这个接口。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。
Dynamic MBean 必须实现javax.management.DynamicMBean接口,所有的属性,方法都在运行时定义。Open MBean和Model MBean都属于Dynamic MBean。
Open MBean Open MBean 与其它动态 MBean 的唯一区别在于,前者对其公开接口的参数和返回值有所限制 —— 只能是基本类型或者 javax.management.openmbean包内的 ArrayType、CompositeType、TarbularType 等类型。这主要是考虑到管理系统的分布,很可能远端管理系统甚至 MBServer 层都不具有 MBean 接口中特殊的类。
Model MBean 与标准和动态MBean相比,你可以不用写MBean类,只需使用javax.management.modelmbean.RequiredModelMBean 即可。RequiredModelMBean实现了ModelMBean接口,而ModelMBean扩展了DynamicMBean接口,因此与DynamicMBean相似,Model MBean的管理资源也是在运行时定义的。与DynamicMBean不同的是,DynamicMBean管理的资源一般定义在DynamicMBean中(运行时才决定管理那些资源),而model MBean管理的资源并不在MBean中,而是在外部(通常是一个类),只有在运行时,才通过set方法将其加入到Model MBean中。

1.2 常用的MBean

JDK 提供了一个 ManagementFactory,帮助我们方便的获取常用的 MBean。可以到 java.lang.management 包下找到这个类看一下注释和代码。

OperatingSystemMXBean

可以获取操作系统相关的信息,机器名称、内存使用、CPU使用等信息。

可通过 ManagementFactory.getOperatingSystemMXBean() 方式获取。

RuntimeMXBean

可以获取当前 JVM 的信息,包括 JVM 参数和 JVM 相关的系统参数。

可以通过 ManagementFactory.getRuntimeMXBean()方式获取。

MemoryMXBean

可以获取当前 JVM 的内存使用,包括堆内存和非堆内存。

可以通过 ManagementFactory.getMemoryMXBean()获取

ThreadMXBean

获取 JVM 线程使用情况,包括活动线程、守护线程、线程峰值等。

可以通过 ManagementFactory.getThreadMXBean() 获取。

ClassLoadingMXBean

获取 JVM 类加载情况,包括已加载类、未加载类等。

可以通过 ManagementFactory.getClassLoadingMXBean() 获取。

GarbageCollectorMXBean

获取 JVM 垃圾收集器的情况,包括使用的哪种垃圾收集器以及回收次数等等。

可以通过 ManagementFactory.getGarbageCollectorMXBeans() 获取,注意,这里获取到的是一个集合,因为垃圾收集器分为老年代和新生代两个。

1.3 MBean和MXBean的区别

java.lang.management包下的MBean为什么是以MXBean结尾,而不是以MBean结尾?以MemoryUsage自定义对象为例,如果MBean服务器的客户端无法访问其属性,则无法管理资源信息。对于非Java语言的MBean服务器的客户端,问题更严重。MXBean框架会将自定义的对象转化为Java平台标准的class(基本类型及javax.management.openmbean包下的类)。JMX通过代理(JMX.newMBeanProxy)的方式兼容MBean和MXBean,两者使用上很相似。

MBean和MXBean的区别

比较 MBean MXBean
命名约定 MBean接口必须以MBean结尾;实现类名称必须为MBean之前的部分(Thing->ThingMBean) MXBean接口以MXBean结尾或者在接口上增加@MXBean;实现类名称无特殊要求(ThatOne->ThingMXBean)
自定义对象 不允许 允许

:① com.sun.jmx.mbeanserver.Introspector#implementsMBean

2.MBeanServer

MBeanServer 是负责管理 MBean 的,一般一个 JVM实例(进程) 只有一个 MBeanServer,所有的 MBean 都要注册到 MBeanServer 上,并通过 MBeanServer 对外提供服务。一般用 java.lang.management.ManagementFactory#getPlatformMBeanServer方法获取当前 JVM 内的 MBeanServer。

3.适配器和连接器

写好的 MBean 注册到 MBeanServer 上之后,功能已经具备了。适配器和连接器就是将这些功能开放出来的方式。 比如 HTTP协议适配器,就是将功能以 HTTP 协议开放出去,这样我们就可以在浏览器使用了。但是 JDK 只是提供了适配器的实现标准,并没有具体的实现,比较常用的是 HtmlAdaptorServer,需要 jmxtools.jar 包的支持。连接器是各种客户端最常用的,JDK 提供的默认连接器是 RMI 连接器,JConsole、VisualVM 都是使用它。

4.JMX客户端

前面提到使用到JMX的诊断工具有,jconsole、jmc、jvisualvm、jprofiler、arthas,各工具直接实现方式相差比较大,下面对一些常用的诊断工具的实现机制简单的说明下。

工具 实现机制 优缺点 说明
jconsole 基于RMI协议 监控本地进程依赖“图形化”桌面 支持本地进程、远程进程;可以添加JMX连接或jstatd连接
jvisualvm 基于RMI协议 监控本地进程依赖“图形化”桌面 支持本地进程、远程进程;可以添加JMX连接
arthas Java Agent 不依赖“图形化”桌面 仅支持本地进程(可以通过Arthas Tunnel服务间接管理远程Agent)

①jstatd:jstatd是jdk(位于%JAVA_HOME%/bin/jstatd.exe)提供的一个RMI Server应用程序,用于监控Java HotSpot VMs的创建和终止,并提供远程监控服务。

②Java Agent:Java Agent是Java 1.5开始提供的一种用于构建独立于应用程序的之外的代理程序。Java 1.5仅支持premain(运行在主程序之前)Agent;Java 1.6开始支持agentmain(运行在主程序之后,arthas采用的就是该方式)Agent。Java Agent用途也很广泛,像arthas、chaosblade混沌工程,具体实现了哪些功能,看看arthas说明文档就知道了,包括基于JMX MBean实现的功能以及在线重定义class、方法调用耗时分析等等。

三、JMX应用场景

1.dashboard监控面板

用于监测和管理JVM的常用资源,比如 JVM 内存、CPU 使用率、线程数、垃圾收集情况等等。

根据需要可以结合OSHI类库(基于JNA的本机操作系统和硬件信息库)一起使用;OSHI可以监控磁盘使用率、网络接口、计算机传感器等。

2.动态修改线上日志级别

以logback为例,只需在logback.xml配置文件中,增加<jmxConfigurator />单行配置即可启动JMX支持。[logback官方示例](

3.查看数据库连接池使用情况

使用过alibaba开源的数据库连接池druid都知道,它有着不错的监控页面,可以查看连接池使用情况、SQL执行历史及执行时间统计,但若是为了性能考虑切换为HikariCP数据库连接池哪?

  • 注册MBean
// 注册MBean com.zaxxer.hikari.pool.PoolBase#handleMBeans(com.zaxxer.hikari.pool.HikariPool, boolean)
hikariDataSource.setRegisterMbeans(true);
hikariDataSource.setPoolName("ceshi");
spring:datasource:hikari:register-mbeans: truepool-name: ceshi
  • 使用日志框架打印连接池使用情况
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// poolName为连接池name,默认规则为
ObjectName poolName = new ObjectName("com.zaxxer.hikari:type=Pool (ceshi)");
HikariPoolMXBean poolProxy = JMX.newMXBeanProxy(mBeanServer, poolName, HikariPoolMXBean.class);
// 获取激活的连接数
int idleConnections = poolProxy.getActiveConnections();

4.查看自定义连接池使用情况

例如以jedisPool连接池为例,它使用commons-pools框架实现,并注册到MBean服务器,你完全可以通过MBean浏览器查看redis连接池使用情况。

5.查看quartz-job任务执行情况

  • 启用JMX

以spring-boot为例,可以在application.yml配置文件中增加如下配置

spring:quartz:properties:org.quartz.scheduler.jmx.export: true# 可选    org.quartz.scheduler.jmx.objectName: "org.quartz.core.jmx:type=QuartzSchedulerMBean, name=ruoyi"

6.通知告警

可通过任务轮询的方式定时获取资源状态并进行邮件、短信、钉钉等通知。

quartz-job自动任务框架为例,QuartzSchedulerMBeanImpl增加了通知机制,我们可以使用jconsole工具“订阅”通知,也可以自己使用java代码订阅并处理。

  • 自定义代码监听通知
        MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();ObjectName poolName = new ObjectName("org.quartz.core.jmx:type=QuartzSchedulerMBean, name=ruoyi");mBeanServer.addNotificationListener(poolName, (notification, handback) -> {// 发送邮件、短信、钉钉通知System.out.println(notification.toString());}, null, null);

四、自定义MBean

虽然 Java 提供了实现 MBean 的标准和规则,但平时我们几乎不需要开发 MBean。绝大多数的开发者接触到的也仅仅是使用 JDK 或者第三方定义好的 MBean,即便是第三方有实现 MBean,也是非常少的。我们知道的有 Tomcat 和 Spring Boot Actuator。

1.MBean接口方式

注意:此种方式不支持自定义对象。

  • HelloMBean
package com.example.demo.mbean;public interface HelloMBean {String getName();void setName(String name);int getAge();void setAge(int age);void print();
}
  • Hello
package com.example.demo.mbean;public class Hello implements HelloMBean {private String name;private int age;@Overridepublic String getName() {return name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic int getAge() {return age;}@Overridepublic void setAge(int age) {this.age = age;}@Overridepublic void print() {System.out.println(name);}
}
  • 注册MBean
package com.example.demo;import com.example.demo.mbean.Hello;
import com.example.demo.mbean.HelloMBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.management.*;
import java.lang.management.ManagementFactory;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);Hello hello = new Hello();hello.setName("张三");hello.setAge(20);// 注册MBeanMBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();try {// 规范 域名(一般用包名):type=接口名,name=MBean名称ObjectName objectName = new ObjectName("com.example.demo.mbean:type=HelloMBean,name=hello");mBeanServer.registerMBean(hello, objectName);} catch (Exception e) {e.printStackTrace();}}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T9lP2B9I-1652448276916)(JMX:Java程序监控的基石.assets/image-20220211112805961.png)]

2.MXBean接口方式

  • Address
package com.example.demo.mbean;import lombok.Data;@Data
public class Address {private String address;private double lng;private double lat;
}
  • HelloxMXBean
package com.example.demo.mbean;public interface HelloxMXBean {String getName();void setName(String name);int getAge();void setAge(int age);Address getAddress();void setAddress(Address address);void print();
}
  • HelloxMXBean
package com.example.demo.mbean;public class Hellox implements HelloxMXBean {private String name;private int age;private Address address;@Overridepublic String getName() {return name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic int getAge() {return age;}@Overridepublic void setAge(int age) {this.age = age;}@Overridepublic Address getAddress() {return address;}@Overridepublic void setAddress(Address address) {this.address = address;}@Overridepublic void print() {System.out.println(name);}
}
  • 注册MBean
package com.example.demo;import com.example.demo.mbean.Address;
import com.example.demo.mbean.Hellox;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);Address address = new Address();address.setAddress("合肥");Hellox hellox = new Hellox();hellox.setName("张三");hellox.setAge(20);hellox.setAddress(address);// 注册MBeanMBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();try {// 规范 域名(一般用包名):type=接口名,name=MBean名称ObjectName objectName = new ObjectName("com.example.demo.mbean:type=HelloMXBean,name=hellox");mBeanServer.registerMBean(hellox, objectName);} catch (Exception e) {e.printStackTrace();}}}

3.Spring Bean方式

1.推荐以Spring Bean className和bean name均以MBean结尾,约定大于配置。

2.同MBean方式,不支持自定义对象。

  • HelloSpringMBean
package com.example.demo.mbean;import org.springframework.jmx.export.annotation.*;@ManagedResource(objectName = "com.example.demo.mbean:name=helloSpringMBean", description = "My Managed Bean")
public class HelloSpringMBean {private String name;private int age;@ManagedAttributepublic String getName() {return name;}@ManagedAttributepublic void setName(String name) {this.name = name;}@ManagedAttributepublic int getAge() {return age;}@ManagedAttributepublic void setAge(int age) {this.age = age;}@ManagedOperation(description = "print")public void print() {System.out.println(name);}
}
  • Bean注入
    @Beanpublic HelloSpringMBean helloSpringMBean() {HelloSpringMBean helloSpringMBean = new HelloSpringMBean();helloSpringMBean.setName("张三");helloSpringMBean.setAge(20);return helloSpringMBean;}

五、参考资料

面试官问我 JMX 了解不,我说:什么?

web 版 JVM 监控器-GitHub源码

arthas-Gitee源码

JMX简单入门

JMX的MBean和MXBean的区别

JMX NOTIFICATION

JMX:Java程序监控的基石相关推荐

  1. Java要抛弃祖宗的基业,Java程序员危险了

    来自:码农翻身(微信号:coderising) 第11代Java国王坐在宝座上,俯视着臣民. 经过历代国王的励精图治,他的Java帝国正处于巅峰状态. 一群大臣看到新王登基,马上上来拍马屁. &quo ...

  2. Java要抛弃祖宗的基业,Java程序员危险了!

    ​第11代Java国王坐在宝座上,俯视着臣民. 经过历代国王的励精图治,他的Java帝国正处于巅峰状态. 一群大臣看到新王登基,马上上来拍马屁. "从后端到手机端,从手机端到大数据,帝国疆域 ...

  3. SCOM2012R2 APM系列(三) 配置Java应用程序监控

    之前写过一篇.NET应用监控的博文,其实那个比较潦草,我自己感觉描述的不够细致,SCOM的应用监控功能是一个很有力的卖点(至少我这么觉得),这次特地拿一个Java应用监控做讲解,我自己在调试的时候也遇 ...

  4. prometheus监控java程序

    可参考链接,需找开发商量jmx端口暴露方式 https://www.jianshu.com/p/8a5e681b18ce 或者 http://www.mamicode.com/info-detail- ...

  5. 监控工具—Prometheus—监控Java程序

    原文作者:青蛙小白 原文地址:Prometheus监控实践:使用Prometheus监控Java应用 目录 1.Prometheus JVM Client 2.Prometheus的服务发现 3.Gr ...

  6. Visualvm监控远程机器上的Java程序

    JDK里面本身就带了很多的监控工具,如JConsole等.我们今天要讲的这款工具visualvm,就是其中的一款.但是这款工具是在JDK1.6.07及以上才有的.它能够对JAVA程序的JVM堆.线程. ...

  7. java程序怎么监控错误_Fundebug上线Java程序错误监控啦!

    原标题:Fundebug上线Java程序错误监控啦! 摘要: Fundebug竭诚为你的Java程序保驾护航. 理论上讲,BUG是无法避免的,实时监控可以帮助开发者第一时间发现BUG,及时修复BUG, ...

  8. win10实时监控用java_利用btrace工具监控在线运行java程序

     一.作用 可以用于对运行中java程序进行诊断监控分析,也可以用于开发阶段查看一些异常信息或者调用过程(如有些第三方代码没有源代码,不便于debug调试). 注:如果用于对在线运行系统的诊断,需 ...

  9. 使用jvisualvm的jstatd方式远程监控Java程序

    使用Java自带的jvisualvm调试Java程序,可以查看CPU.内存.类及线程等信息,还可以进行Dump,无疑是一个利器 由于客户端是Windows.服务端是Linux,并且是最小安装的Linu ...

最新文章

  1. JSP第二次作业_7小题
  2. 心得丨走过最长的路,就是机器学习过程中的弯路
  3. “另一个程序正在使用此文件,进程无法访问”的解决方法
  4. deepin--更改最低亮度
  5. ButterKnife与RxBinding中文件重复问题解决
  6. jsoncpp和rapidjson哪个好用?
  7. 递归函数里面又有2个调用自身的递归函数里面参数变化总结
  8. Git常用指令——持续补充中
  9. LeetCode(705)——设计哈希集合(JavaScript)
  10. 随笔之:VC操作Word系列(四)
  11. 堆排序建堆复杂度在特殊情况下的推导
  12. Mapv 是地理信息可视化开源库
  13. springboot+freemarker毕业设计项目错误合集
  14. CSDN的访问数据,真是破绽百出
  15. “阿里云开放平台俱乐部”首站启航
  16. 基于java+SpringBoot+HTML+Mysq幼儿园日常管理系统
  17. select默认选中及赋值问题
  18. GD32库中常用的位操作REGIDX_BIT(regidx, bitpos)
  19. React 360 全景VR交互项目实战
  20. Python爬取网页图片

热门文章

  1. 迪赛智慧数——饼图(环形饼图):预制菜消费群体分析
  2. 微信小程序实现“红包雨”
  3. 第5章 uniapp开发ImoocBlog
  4. amxmodx服务器每局时间无法修改,CS1.6反恐精英1.6 v3266葫芦修改版
  5. Linux下CS程序开发,Linux_Linux玩CS反恐精英的方法,一、下载必要的软件包 我们 - phpStudy...
  6. 计算机VB运算符号的优先级,VB.Net运算符优先级
  7. FANUC机器人DCS相关报警及处理对策
  8. SQL查询计算近几天,近几个季度,近一年的数据
  9. 动态面板:登录面板切换
  10. python3.7.4安装教程桌面_Python3.7.4图文安装教程