JMX的学习笔记
1. JMX简介
JMX(Java Management Extemsions) 是一个为应用程序、设备、系统等植入管理功能的框架。
JMX 是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理。主要用于对JAVA应用程序和JVM进行监控和管理。JConsole和JVisualVM中能够监控到JAVA应用程序和JVM的相关信息都是通过JMX实现的。
JMX 规范可以分为三层:设备层,代理层,分布式服务层。设备层规范定义了编写可由JMX管理的资源的标准,即如何写MBean;代理层规范定义了创建代理的规范,封装了MBean Server;分布式服务层主要定义了对代理层进行操作的管理接口和构件。
如果一个Java对象可以由一个遵循JMX 规范的管理器应用管理,那么这个Java对象就可以称为一个可由JMX 管理的资源。
要使一个Java对象可管理,则必须创建相应的MBean对象,并通过这些MBean对象管理相应的Java对象。当拥有MBean类后,需要将其实例化并注册到MBeanServer上。一共有四种类型的MBean,分别是标准类型MBean,动态类型MBean,开放类型MBean和模型类型MBean。
资源管理
JMX涉及到的是监控和管理,核心是针对资源的一系列操作。那什么是资源?只要能帮助使你的活动和系统正常运转的都算资源。对于一个应用来说,资源可以是:
- 硬件设备
- 计算机网络
- 操作系统
- 运行服务器
可以称之为资源的远远不止这些,比如运行这些的人员和开发者,也就是人力资源等。我们需要做的就是对它们进行监控和管理,监控是为了及时发现问题,以便能够及时提出正确的解决方案,避免损失;管理是为了预防问题的发生,同时也是为了使资源能够得到有效的利用,使利益最大化。在监控和管理的时候要考虑的方面如下:
- 监控硬件和平台的运行情况:包括服务器和操作系统等;
- 合理配置资源:比如内存的配置是否合理,CPU是否足够强大;
- 收集应用运行的情况:比如说访问量多大,响应时间是否够快,那个地区的访问人数最多;
- 在应用发生异常时能够及时定位问题所在:这是监控的核心之一;
关于上述,JMX都能很好的支持。
术语介绍
管理资源
管理资源(Manageable resource):只要是能帮助使你的活动和系统正常运转的都算资源,可以是硬件、也可以是应用,只要能够被Java的类描述即可;
管理组件
管理组件(MBean,managed bean):从资源的角度来看,它是一个对抽象的资源的一个描述,比如说如果资源是数据库,管理组建中可以提供数据库的一些描述信息,比如数据库服务器的运行地址、端口,类型以及最大连接数等等,但是这个类必须满足JMX规范中的提出的要求,比如命名规则和实现标准,类似于JavaBean
。由于管理组件是资源的抽象,所以管理应用是直接面向MBean,也就是说MBean会被暴露给管理应用来操作和访问,通过MBean中提供的属性和方法。
管理组件服务器
管理组件服务器(MBean Server):简单的来看,它是一个容器,用来盛装和管理一组MBeans,它是整个JMX管理环境的核心,由于其中有很多的MBean,所以它必须提供一种机制来区分各个MBean,这就是注册机制,每个添加到MBean Server的MBean 在注册的时候都要提供一个ObjectName来区分彼此,MBean Server通过这个ObjectName来查找每个MBean,在JMX中是通过ObjectName类来为每个MBean提供唯一的一个标识,它包括两部分:
- 域名:这个域名通常是和想要注册到的MBean Server的名称标识相同,以便根据功能模块区分不同MBean server 中的MBean;
- 键值对列表:被用来唯一的标识MBean,也提供了关于该MBean的信息,形式如下:HelloAgent:name=helloWorld;其中的属性不一定是真实的MBean的属性,仅仅要求当和其他的MBean比较的时候能够唯一标识,每个ObjectName中都要至少有一个属性;
当ObjectName重复的时候,注册的时候会抛出 javax.management.InstanceAlreadyExistsException。
JMX代理
JMX代理(JMX Agent):它提供一系列的服务来管理一系列的MBeans,它是MBean Server的容器。JMX代理提供一些服务,包括创建MBean之间的关系,动态加载类,简单监视服务,以及计时器;代理可以有一系列的协议适配器(Protocal adapters)和连接器(connectors),协议适配器和连接器也是Java类,通常情况下也是MBeans,这些适配器和连接器是提供转接功能而存在的,以便可以在远程使用不同的协议,通过客户端与这个代理连接,它内部可以映射到一个外部的协议或者暴露代理给远程连接,这就意味着JMX代理可以被一系列不同的管理协议和工具是用那个,在本质上是插件式架构的一种体现,体现了可插拔的思想;
协议适配器和连接器
协议适配器和连接器(Protocal adapters and connectors):协议适配器和连接器是JMX Agent中的对象,将代理暴露给不同的管理应用和协议,这个和不同的数据库的驱动程序类似,每个数据库都有自己的一套协议来联系,为了保持进行连接,就需要在JDBC应用和数据库服务器之间通过不同的驱动程序关联。一个JMX Agent可以有任意数量的适配器和连接器;它们也是MBeans;
通知
通知(Notification):通知是由MBeans和MBean Server提出的,其中封装了具体的事件和相应的数据。其他的MBeans或者Java对象可以注册作为监听器来接受这些通知,其实就是观察者设计模式在JMX中的应用。
2. JMX架构分层
1. 分层介绍
JMX的架构是组件式的,被设计为三层:
- 分布层(Distributed layer):包含可以使管理应用与JMX Agents交互的组件。一旦通过交互组件与JMX Agents建立连接,用户可以用管理工具来和注册在Agents中的MBeans进行交互;
- 代理层(Agent layer):包含JMX Agent以及它们包含的MBean Servers。Agent layer的主要组件是MBean server,作为JMX Agents的核心,它充当MBeans的注册中心。该层提供了4个Agent 服务来使对MBean 的管理更容易:计时器(Timer)、监控(monitoring)、动态加载MBean(dunamic MBean loading)、关系服务(relationship services);
- 指示层(Instrumentation layer):包含代表可管理资源的MBeans。该层是最接近管理资源的,它由注册在Agents中的MBeans组成,这个MBean允许通过JMX Agent来管理。每个MBean都暴露出来针对底层资源的操作和访问;
2. MBean 与MXBean的介绍
MBean介绍
MBean也是JavaBean的一种,在JMX中代表一种可以被管理的资源。一个MBean接口由属性(可读的,可能也是可写的)和操作(可以由应用程序调用)组成。MBean可分为如下四种:
类型 | 描述 |
---|---|
standard MBean | 这种类型的MBean最简单,一个标准的MBean由一个MBean接口(该MBean接口列出了所有被暴露的属性和操作对应的方法)和一个class (这个class实现了这个MBean接口并提供被监测资源的功能)组成(接口和 class必须放在同一个包下,不然会出错)。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。标准MBean只能操作基本数据类型,如int、dubbo、lang等 |
dynamic MBean | 必须实现javax.management.DynamicMBean接口,所有的属性,方法都在运行时定义 |
open MBean | 此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中。 |
MXBean
MXBean是MBean的一种。MXBean与MBean一样都需要定义一个接口和class类,但是MXBean并不要求Java类的名称必须与接口名称的前部分相同。另外MXBean中还可以正常使用自定义数据类型;如果在MBean中使用自定义数据类型的话,通过JConsole查看时会显示不可用。当MXBean中使用被转换成CompositeDataSupport类。
区别
标准MBean与MXBean的区别
- 在标准MBean中使用自定义数据类型时,JConsole中会显示不可用;而在MXBean中可以正常所使用。
- 在标准的MBean接口中与class的命令必须遵守一定规范,而MXBean的接口与Class的命名没有约束条件。
3. JMX的使用
标准MBean 使用规范
标准的MBean由一个MBean接口和一个Class类组成,并且接口必须命名为xxxMBean而Class类名必须为xxx 放在同一个包下,如、若不在同一包下运行时将出异常。
JMX的使用步骤
定义接口与资源实体类,接口中定义属性与操作;get表示可读,set表示可写。
创建Agent类。
a. 创建MBeanServer,相当于管理MBean的容器,创建方式有两种——获取JVM中默认启动的MBean server 或者 自己创建。 b. 创建ObjectName,用于标识唯一的资源MBean,格式为:“域名:name=MBean名称”。 c. 绑定MBean与对应的ObjectName并注册到MBeanServer。 至此即可通过JConsole管理本地的MBean的相关信息了,同事也可以提供其他的连接方式,如: 3. rmi连接方式。 a. 注册监听端口号 b. 创建JMXServiceURL,格式为:service:jmx:rmi://localhost:0/jndi/rmi://localhost:1099/jmxrmi (完整版) c. 创建jmxConnectorServer,绑定MBserver与Url。 4. HtmlAdaptor连接管理方式(需要引入jmxtools.jar)。 a. 创建Html适配器,并设置监听端口。 b. 创建适配器ObjectName,绑定Html 适配器并注册到MBeanServer。 c. 开启适配器。
JMXServiceURL格式说明
- service:jmx:rmi://localhost:0/jndi/rmi://localhost:1099/jmxrmi 中
localhost:0
这一部分可以省略掉 service:jmx
:这个是JMX URL的标准前缀,所有的JMX URL都必须以该字符串开头,否则会抛MalformedURLExceptionrmi
:这个是jmx connector server 的传输协议,在这个url中是使用rmi来进行传输的localhost:0
:这个是jmx connector server 的IP和端口,也就是真正提供服务的host和端口,可以忽略,那么会在运行期间随意绑定一个端口提供服务。jndi/rmi://localhost:1099/jmxrmi
:这个是jmx connector server的路径,具体含义取决于前面的传输协议。比如该URL中这串字符串就代表着该jmx connector server的stub是用用jndi api 绑定在rmi://localhost:1099/jmxrmi
这个地址
具体使用实例:
public static void init(LoggerContext loggerContext) throws Exception {
mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN_NAME);
// 注册服务
ObjectName objectName = new ObjectName(DOMAIN_NAME + ":name=" + RELOAD_CONFIG_NAME);
jmxConfigurator = new JMXConfigurator(loggerContext, mBeanServer, objectName);
mBeanServer.registerMBean(jmxConfigurator, objectName);
// htmlAdaptor 注册连接
htmlAdaptorServer = new HtmlAdaptorServer();
htmlAdaptorServer.setPort(HTML_PORT);
objectName = new ObjectName(DOMAIN_NAME + ":name=" + CONNECTOR_NAME);
mBeanServer.registerMBean(htmlAdaptorServer, objectName);
htmlAdaptorServer.start();
// rmi方式
//这句话非常重要,不能缺少!注册一个端口,绑定url后,客户端就可以使用rmi通过url方式来连接JMXConnectorServer
LocateRegistry.createRegistry(RMI_PORT);
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + RMI_PORT + "/logback_config");
jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mBeanServer);
jmxConnectorServer.start();
}