【这是一猿小讲的第 44 篇原创分享】
先聊聊最近比较流行的梗,来一次灵魂八问。
配钥匙师傅: 你配吗?
食堂阿姨: 你要饭吗?
算命先生: 你算什么东西?
快递小哥: 你是什么东西?
上海垃圾分拣阿姨: 你是什么垃圾?
滴滴司机: 你搞清楚自己的定位没有?
理发师傅: 你照照镜子看看你自己,觉得行吗?
小区保安: 你是谁? 你从哪里来? 要到哪去?
顺着这个梗,作为身经百战的研发人员,我们继续进行灵魂追问。
程序员: 获取应用的系统指标信息,你能取吗?
程序猿: 动态修改应用的参数信息,你能改吗?
程序媛: 远程实现应用服务的重启,你会启吗?
如果架不住灵魂拷问,那我们就潜心修炼一下,今天要分享的大猪蹄子(主角)—— JMX。
1 .
The Java Management Extensions (JMX) API is a standard API for management and monitoring of resources such as applications, devices, services, and the Java virtual machine. The JMX technology was developed through the Java Community Process (JCP) as Java Specification Request (JSR) 3, Java Management Extensions, and JSR 160, JMX Remote API. ——摘自官网定义。
其实约莫能够认识到,JMX 是 Java 管理扩展,主要用于管理和监视诸如应用程序、设备、服务和 Java 虚拟机等资源的标准 API。JMX技术是通过 JCP 制定开发,由 JSR 3 和 JSR 160 规范定义而成。
JCP:是 Java Community Process 的缩写,是一个主要由Java开发者以及被授权者组成的开放的国际组织,职能是开发和修订 Java 技术规范。
JSR:是 Java Specification Requests 的缩写,这个咱们之前已经谈及过,再稍微再多说两句。JSR 是指向 JCP 提出新增一个标准化技术规范的正式请求,是 Java 界的一个重要标准,任何人都可以提交 JSR ,以向 Java 平台增添新的 API 和服务。
JSR 3:Java 管理扩展(JMX)规范。
JSR 160:Java 管理扩展(JMX)远程API。
JSR N: 访问 https://www.jcp.org/en/jsr/detail?id=N 直接修改传入对应的 JSR 的编号 N,就可以查询规范的更多细节。
2 .
面对灵魂的拷问: 获取应用的系统指标信息,你能取吗 ?
灵魂深处的回答: 必须当然能取 !接下来就告诉你怎么取。
无论是程序初哥还是骨灰级战神,大概率都会知道,获取应用的系统指标信息,无非就是监控数据直接落盘;被监控的应用提供接口喷指标数据等方式,来完成应用监控指标的输出。
监控数据直接落盘的方式,可以细分为落到磁盘文件、写入共享存储例如 redis。其中落入磁盘文件,可以基于咱们之前谈及的 flume 等开源的轮子完成数据采集;其中写入 redis 的,监控管理应用,可以直接读取指标数据使用就行。
被监控的应用提供接口喷指标数据的方式,无非就是被监控的应用,提供一个能喷监控数据的入口,司空见惯的实现,便是提供http 接口,然后再来一个监控管理的应用,再画点页面进行展示监控指标。
上面的实现方式,大体用一幅图汇总如下。
其实上面这些实现方式都不是本次的重点,如果你稍微了解一下 JMX,则会惊喜的发现,上面的实现都相对比较繁琐,因为 Java 中已经实现了大部分系统监控指标的获取,并且提供 HTML 页面来展示监控指标,非特殊情况下,其实无需再为监控管理应用,单独再开发展示界面啦。
3 .
感觉 JMX 是很丰满,不知道现实是否会很骨感呢。也是时候撸点 简单 的代码与 JMX 正式打个照面啦,JMX 应用的开发流程我简单划分为四步走。
第一步:按照 JMX 规范,定义一个 Java 接口,用来暴露可被访问和操作的信息。要注意: JMX的规范要求,接口的命名必须是实现类的名字后加 MBean 。一口吃不了胖子,咱们还是从最简单的代码开始撸起。
public interface AppMBean {
public void welcome();
}
第二步:按照 JMX 规范,定义要被管理的 MBean,其实就是实现了上一步接口定义的一个普通的 Java 类。
public class App implements AppMBean {
@Override
public void welcome() {
System.out.println("JMX 初体验,So easy!");
}
}
第三步:把实现的 MBean 注册到 MBean 服务器上,照着做就行啦,熟能生巧,莫纠结。
import javax.management.*;
import java.lang.management.ManagementFactory;
public class AppAgent {
public static void main(String[] args) throws Exception {
// 建立一个MBeanServer,用来管理MBean
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// 创建AppMBean对象
App mbean = new App();
// 为AppMBean 创建ObjectName实例
ObjectName name = new ObjectName("com.example.mbeans:type=App");
// 将AppMbean对象注册到MBeanServer上去
mbs.registerMBean(mbean, name);
// Wait forever
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}
第四步:通过 JDK 自带工具或代码访问定义的 MBean。
不妨先带你们玩一下 JDK 自带的 JConsole,打开控制台敲入命令:jconsole(前提是安装了JDK),效果如下。
哎呦,我去效果确实不错,什么内存、线程、类以及 MBean 信息应有尽有,自己私下可以着重关注 MBean信息,触发一下方法调用, 说一千道一万,不如自己点点看 。
趁着热乎劲,再带你们玩一下 JDK 自带的 jvisualvm,打开控制台敲入命令:jvisualvm(前提也是安装了 JDK),效果如下。
哎呦,我去,效果同样杠杠滴,什么内存、线程、类以及MBean信息应有尽有,关键是长得也好看, 夸一千道一万,其实不妨自己点点看。
说实话,还真想多撸点代码,看一看效果。其实还是想再偷点懒,尝试使用一下 sun 自己实现 jdmk 工具包 jmxtools,前方高能预警,有坑,有坑,不过先不填!
首先导入 jmxtools 依赖包。
<dependency>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
<version>1.2.1</version>
</dependency>
接着修改第三步中的 AppAgent,代码如下。
import com.sun.jdmk.comm.HtmlAdaptorServer;
import javax.management.*;
import java.lang.management.ManagementFactory;
public class AppAgent {
public static void main(String[] args) throws Exception {
// 建立一个MBeanServer,用来管理MBean
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// 创建AppMBean对象
App mbean = new App();
// 为AppMBean 创建ObjectName实例
ObjectName name = new ObjectName("com.example.mbeans:type=App");
// 将AppMbean对象注册到MBeanServer上去
mbs.registerMBean(mbean, name);
// Wait forever
//System.out.println("Waiting forever...");
//Thread.sleep(Long.MAX_VALUE);
//创建一个AdaptorServer,AdaptorServer也是一个MBean,提供MBean的HTML管理界面。
ObjectName adapterName = new ObjectName("com.example.mbeans:name=htmladapter,port=8888");
HtmlAdaptorServer adapter = new HtmlAdaptorServer(8888);
mbs.registerMBean(adapter, adapterName);
adapter.start();
}
}
此时,坑已经备好,就等你来入坑,发现 jmxtools-1.2.1.jar 死活下载不下来,打破砂锅追到底。
https://repo1.maven.org/maven2/com/sun/jdmk/jmxtools/1.2.1/jmxtools-1.2.1.jar
居然 Jar 包下载链接 已经是 404 啦,Jar 包已经在茫茫宇宙中走丢啦!!!
那只能通过野路子下载一个这样的 Jar 包啦,然后在项目下创建 lib 目录,并把 jmxtools-1.2.1.jar 包放进去,修改依赖为本地引入。
<!-- jmxtools -->
<dependency>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
<version>1.2.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/jmxtools-1.2.1.jar</systemPath>
</dependency>
然后再运行 AppAgent,访问 http://localhost:8888/ 一探究竟。
其实看起来也挺爽,除了颜值差点劲,功能还凑合,二次包装包装应该也可以用。
4 .
好了,跟着我的脚步一起走到这儿的,那绝对都是真爱啊!
不过此时你内心是否会有这样的疑问: 咱们既没有定义获取内存的方法,也没有定义获取线程等方法定义,但是页面的这些数据从哪儿来的呢?
另外,当我们看源码时也会发现诸多 M X Bean 的定义, 那 到底 MX Bean 又是啥呢? MBean 与 M X Bean 啥区别呢? 下图摘自resin-4.0.55 的源码,会发现很多 MXBean 定义。
有疑问不可怕,本次的很多疑问先欠着你们。欲知答案如何,咱们且听下回分解。
最后如果感觉有点帮助,不妨锻炼一下手指点个在看,或者再来个疯狂分享转发,因为你的每一次分享,我都认真当成了鼓励与喜欢。
推荐阅读:
玩弄日志归集于手掌之中
爱情36技之暗送秋波的技术
一篇文章讲透线上应用监控