导语
JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
JMX在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等
优点是可以非常容易的使应用程序被管理
伸缩性的架构使每个JMX Agent服务可以很容易的放入到Agent中,每个JMX的实现都提供几个核心的Agent服务,你也可以自己编写服务,服务可以很容易的部署,取消部署。
主要作用是提供接口,允许有不同的实现
JMX 最常见的场景是监控Java程序的基本运行状况,任何Java程序都可以开启JMX,然后使用Java监控工具来进行查看。为Java应用程序开启JMX非常简单,之主要在运行的Java程序的命令后面加入下面这些命令即可
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote.port=1000
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
然后就可以通过监控工具看到有关的内容。例如使用Java自带JConsole 通过JMX展示的信息,可以获取到内存情况、线程情况、类加载情况等等
当然在JMX中它所能提供的功能还远远不止这些,针对一些具体程序的专有信息也提供了响应的接口,并且可以在JConsole中进行展示。也就是说在编写代码的时候可以把信息封装到一个MBean的Java 对象中,然后JConsole会连接到JMX服务,识别MBean并且在图形化界面中进行展示。
从抽象的角度出发类似于浏览器发送一个请求给服务器,然后服务器返回对应的请求数据。从某种意义上讲,所有的有关JVM的监控机器,与JMX的通信原理与这个类似,只不过不是通过HTTP协议,而是基于一种客户端服务器的工作模式。这种工作模式相对于HTTP来说,JMX实现起来相对会比较简单。例如如果需要知道服务器上运行中程序的相关信息,执行了多少次数据库操作、任务队列中有多少个任务等待处理等等。
在日常的工作中最常用的处理方式就是在应用程序中启动一个HTTP服务,类似于SpringBoot的监控,当收到来自客户端的请求的时候返回一些HTTP处理的信息,然后转换成JSON格式的数据返回给客户端,客户端会解析这个JSON数据来进行展示。JMX也是基于这种模式,只不过就是数据交换方式有所不同。下面就来看看在Zookeeper中怎么实现这个操作的。
首先在org.apache.zookeeper.jmx包中就是Zookeeper对于JMX的操作进行了封装。如下代码所示
由于在这里是对JMX的扩展并没有严格的按照MBean这种方式进行接口编写。在代码注释中也看到了有关的说明。
/**
* Zookeeper MBean info interface. MBeanRegistry uses the interface to generate
* JMX object name.
*/
public interface ZKMBeanInfo {
/**
* @return a string identifying the MBean
*/
public String getName();
/**
* If isHidden returns true, the MBean won't be registered with MBean server,
* and thus won't be available for management tools. Used for grouping MBeans.
* @return true if the MBean is hidden.
*/
public boolean isHidden();
}
如图所示在Zookeeper中其实对于很多的地方都进行了监控。所以具体实现的Bean对象也是有很多。可以根据Bean的名称来获取到具体都是支持哪些内容的监控
在Zookeeper中的org.apache.zookeeper.jmx.MBeanRegistry 类就是提供了这个功能在这类中有一个register()方法,如图所示,由于代码复制在这个地方会变形,所以使用了图片的方式。
上面代码最为关键的一个地方就是下面这行代码,有了这行代码,在JConsole中就可以看到其中有那些操作。
在上面代码中加入一些LOG日志,使用DEBUG级别启动来查看最终的效果
结果如下
&emps;由于截图的原因,这里截图比较小。需要的话可以点击图片进行放大。会看到这里注入的是主线程本身和一个DataTreeBean。在上面截图中也看到的DataTreeBean。但是实际上会看到 它的名称是
其名称 org.apache.ZooKeeperService:name0=StandaloneServer_port2181,name1=InMemoryDataTree 也就是说我们要使用JConsole连接之后找到这两个其中一个就说明我们的分析是正确的。如果两个都找到就说明这个机制是没有问题的。
在配置好Java环境变量的任意命令行中输入
jconsole
然后就进入到了如下的页面中
选择对应的线程双击连接会看到如下的界面找到MBean即可
会看到确实有来自Zookeeper的MBean点击之后会看到
到这里所有的分析都很清楚,到这里会看到,这里为什么会使用这个机制,或者说在Zookeeper中使用这个机制是需要做什么样的操作,下面就进入分析阶段
前面的分析中提到了一个方法Zookeeper中的register()方法,下图展示了都是在什么地方调用了这个方法,调用这个方法之后分别都进行的操作是什么。根据上面的分析知道,在启动的时候注入了两个MBean这个是通过单机模式启动的。
开始注入 JMX MBean org.apache.zookeeper.server.ZooKeeperServerBean@670b40af 其名称 org.apache.ZooKeeperService:name0=StandaloneServer_port2181
开始注入 JMX MBean org.apache.zookeeper.server.DataTreeBean@46daef40 其名称 org.apache.ZooKeeperService:name0=StandaloneServer_port2181,name1=InMemoryDataTree
下面来看看集群模式启动的时候回注入那些操作,从下面的结果中可以看到,集群模式启动的时候,所注入MBean的内容要比单机模式启动的时候注入的MBean要多,而这些MBean从内容上来看都是与Leader的选举相关的东西。而在下面图中展示的注册方法调用的时候也确实前三个就是对Leader选举操作有关的内容。也就是说其实在Zookeeper集群中,是通过这种方式来管理集群中所有的节点数据属性存储
开始注入 JMX MBean org.apache.zookeeper.server.quorum.QuorumBean@2c647f16 其名称 org.apache.ZooKeeperService:name0=ReplicatedServer_id1
开始注入 JMX MBean org.apache.zookeeper.server.quorum.LocalPeerBean@6c0dc17b 其名称 org.apache.ZooKeeperService:name0=ReplicatedServer_id1,name1=replica.1
开始注入 JMX MBean org.apache.zookeeper.server.quorum.RemotePeerBean@1356e8a 其名称 org.apache.ZooKeeperService:name0=ReplicatedServer_id1,name1=replica.2
开始注入 JMX MBean org.apache.zookeeper.server.quorum.RemotePeerBean@7ff0e9e 其名称 org.apache.ZooKeeperService:name0=ReplicatedServer_id1,name1=replica.3
开始注入 JMX MBean org.apache.zookeeper.server.quorum.LeaderElectionBean@2d9461d5 其名称 org.apache.ZooKeeperService:name0=ReplicatedServer_id1,name1=replica.1,name2=LeaderElection
通过JMX技术来支持整个的Zookeeper集群的信息维护,可以减少通过网络传入或者是IO操作带来的传输效率上的消耗,将更多的性能转而提供给其他的操作。对于基础信息的维护再也不用多消耗其他资源而是由语言本身的特性来完成。同时利用这种操作可以通过JConsole来管理进行监控操作。在很多的场景下都是比较适用的。这也为后续系统性能监控提供了一种解决方案。当然有优势就有这个优势所来带的不足,希望可以辩证的使用技术组合构建高效工具