老技术新谈,Java应用监控利器JMX(2)
各位坐稳扶好,我们要开车了。不过在开车之前,我们还是例行回顾一下上期分享的要点。
上期由于架不住来自于程序员内心的灵魂的拷问,于是我们潜心修炼,与 Java 应用监控利器 JMX 正式打了个照面。
JMX 在我看来可谓是如陈年老酒般越品越有味,通过品这款老酒,我们认识了 Java 中你可能从未相识的名词 JCP、JSR;又耍了一把 JDK 内置的两款基于 JMX 的可视化监控、管理工具 JConsole 以及漂亮的 jvisualvm ;同时我们又感受了一下长得虽然不咋滴,但是功能还算可以的 jmxtools 工具包。
用一句话简单总结:JMX 是真香!如果你还未感受到她的魅力,也没关系,相信通过近期的几篇分享会让你深深的爱上她。
大家是否还记得,上期最后遗留了几个疑问,我们再简单梳理梳理,不妨今天就来个各个击破。
遗留疑问1:当我们看源码时也会发现诸多 XxMXBean 的定义,那到底 MXBean 又是啥呢?MBean 与 MXBean 啥区别呢?
遗漏疑问2:咱们既没有定义获取内存的方法,也没有定义获取线程等方法定义,但是 JConsole 等管理页面上展示的数据从哪儿来的呢?
好了,怀揣着疑问,正式开始我们今天的分享。
1.
其实讲真,虽然咱们已经与 JMX 打了个照面,但是还是应该从全局架构上再深入的挖一挖、处一处。
如上图所示,JMX 的全局架构从下至上主要分为资源层、代理层、适配层。其中资源层主要定义被管理的 MBean,也就是被监控的应用;代理层主要用于注册和管理 MBean;适配层也称为连接层,主要实现了各种连接协议,如 HTTP、RMI、SNMP。
那个远程管理层主要是指咱们的监控管理应用,理解成客户端就行了。
架构搞懂个七七八八,了解个全局的梗概,那不妨回头看看上期一起撸的代码,结合代码来一次对号入座。
其实细心的猿粉早已经发现,上期的代码中根据文件名称应该能猜个八九不离十。
App 类,就代表要进行监控的资源(应用),对应就是资源层; AppMBean 接口,代表代理层可以对监控的应用进行哪些操作; AppAgent 类,见名知意,对应的是代理层; jmxtools 、jconsole、jvisualvm 工具,对应的就是远程管理应用。
确实是那么回事,确实有点儿意思。
2.
说一千道一万,终究还是没有解决咱们的疑问:当我们看框架源码时会发现诸多 XxMXBean 的定义,那到底 MXBean 是啥呢?MBean 与 MXBean 啥区别呢?那我们不妨从官网搜罗搜罗。
The MXBean concept provides a simple way to code an MBean that only references a predefined set of types, the ones defined by javax.management.openmbean. In this way, you can be sure that your MBean will be usable by any client, including remote clients, without any requirement that the client have access to model-specific classes representing the types of your MBeans. ——摘自官方档,感兴趣的可以通过如下链接进行仔细品味品味。
https://docs.oracle.com/javase/8/docs/api/javax/management/MXBean.html
其实约莫就是说:
MXBean 提供了一种简单的方法来编写引用自定义类型的 MBean; 通过 MXBean,可以确保 MBean 被任何客户端使用,而不需要客户端关心 MXBean 中引用类型的类。
但是我估计你依然还是很茫然啊,依然还是很懵逼,那不妨举个栗子吧。
首先在上期分享的代码基础之上,为我们的 App 应用配备一条看门狗 Watchdog。
接着给被管理的应用 App 加入看门狗 Watchdog。
然后在 AppMBean 接口中暴漏操作方法。
紧接着在代理层 AppAgent 创建一条看门狗,并给 App 加上。
代码秒撸完,跑起来看一看,一切就绪,请出应用管理工具 JConsole 玩一玩,天啦撸!发现看门狗的值居然显示不可用?!
这不是 Bug,不过请你务必记住 MBean 的这个效果,因为一会儿就被搞没了。那接下来不妨把 AppMBean 修改为 AppMXBean。
接着把 App 实现的接口也替换为 AppMXBean。
代码瞬间就改完,还是需要跑起来看一看,一切又准备就绪,再请出 JConsole 耍一耍。
出乎意料看门狗居然有值啦,而且是 javax.management.openmbean.CompositeDataSupport,天啦噜,这是啥?点点看看有没有惊喜。
果不其然,点完瞬间清晰,原来是看门狗的值,厉害厉害。
好了,演示接近尾声,那你搞懂了没?其实说白了 MXBean 就是比 MBean 多了个牛 X(叉),支持自定义引用类型的数据展示。
3.
搞定了 MXBean 与 MBean的区别,针对「既没有定义获取内存的方法,也没有定义获取线程等方法定义,但是监控页面上展示的那些内存等数据到底从哪儿来的呢?」的问题,那不妨再扒一扒 JDK 的 API ,咱们有没有良方能对症。
我们先扒一扒 JDK 5 的 API,会发现 java.lang.management 包下存在诸多内置的 MXBean 定义。
https://docs.oracle.com/javase/1.5.0/docs/api/index.html?java/lang/management/package-summary.html
我们再扒一扒 JDK 8 的 API,同样会发现 java.lang.management 包下存在诸多内置的 MXBean 定义,而且随着 JDK 版本的提升,MXBean 也逐渐增多啦。
https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/management/package-summary.html
到这一步,迷茫疑惑的我们,应该稍微清晰了不少,但是做学问有些时候,还是需要打破砂锅问到底,这些到底都是干啥用的?那不妨把 JDK 5 与 JDK 8 中共性的 MXBean 定义,画个脑图彻底解释一下,因为有些在工作中确实会用到。
我相信通过上面的的手册,再去深入中间件也好、开源的框架也罢,肯定会遇鬼杀鬼、顺风顺水。
4.
程序猿灵魂拷问:动态修改应用的参数信息,你能改吗?
是时候再一次正式面对程序猿的灵魂拷问啦,那面对这个灵魂拷问,该何解?
接下来容我慢慢絮叨,先说说解决思路:是否可以把需要配置的参数放在一个 MBean 中,然后考虑到方便,再提供了一个管理配置页面,这样是否可行呢?咱们还是写段代码验证一下可行性。
首先定义一个参数配置的接口 ConfigMXBean。
然后定义被管理对象 Config,并且实现 ConfigMXBean 接口。
接着编写代理层 ConfigAgent,并采用 jmxtools 提供页面管理。
代码编写完,跑起来探一探,然后浏览器访问 http://localhost:8888/ 效果如下。
当我们选择true,并点击 Apply,控制台输出为true。哇塞!很神奇,亲测可用。
好了,分享一个不重启应用,而动态修改参数的一个简单实现思路,其实这个能干什么事情,比如使用 JMX 可以作为应用的开关,可以做一些新老功能的切换以及动态修改风险评分级别等等,自行脑补一下吧。
5.
说句掏心窝的话,我为什么要分享这个技术点?因为很多开源的轮子以及中间件,大概率都有这种实现方式,例如数据库连接池 Druid 使用了 JMX 来进行自身的监控;例如 Resin、Tomcat、weblogic等等,打娘胎里都提供了JMX服务,所以还是很有必要梳理梳理,然后分享给你们,万一你们也能用到呢(捂嘴笑)。
好了,今天的车要到站了,还有很多应用场景没有说,咱们还是且听下回分解吧,真心希望一猿小讲的每篇分享都能帮到你一点点,最后预祝各位在今后的日子里,大鹏展翅同风起、扶摇直上九重天。