背景
前段时间在看btrace源码和jdk一些源码的时候,经常会看到一些jmx的相关内容。以前对jmx基本是一片空白区,花了点时间学习记录下。
过程
jmx总体架构图:
说明:
1. Agent : javax.management.MBeanServer实现了Agent的功能,以标准的方式给出了管理系统访问 JMX 框架的接口
2. SubAgent: javax.management.MBeans实现了SubAgent的功能,以标准的方式给出了 JMX 框架访问资源的接口
MBean是Management Bean的缩写,负责将可管理资源和服务封装成类似Java Bean的形式。通过MBean的特性可以访问可管理资源的各类信息。MBean对资源的封装体现在以下几个方面:
* 属性名称及读写类型。
* 对资源的操作。
* 指定类型的通知。
从MBean的实现上来看,MBean分为两种类型:
- 标准(Standard)MBean
- 动态(Dynamic) MBean , 又进一步可分为Open MBean和Model MBean
Opean Mbean:与其它动态 MBean 的唯一区别在于,前者对其公开接口的参数和返回值有所限制。只能是基本类型或者 javax.management.openmbean 包内的 ArrayType、CompositeType、TarbularType 等类型。考虑到管理系统的分布,很可能远端管理系统甚至 MBServer 层都不具有 MBean 接口中特殊的类。
Model Mbean: 普通的动态 Bean 通常缺乏一些管理系统所需要的支持,JMX 提供商都会提供不同的 ModelBean 实现。其中有一个接口是 Java 规范中规定所有厂商必须实现的:javax.management.modelmbean.RequiredModelBean。通过配置 Descriptor 信息,我们可以定制这个 Model Bean, 指定哪些 MBean 状态需要记入日志、如何记录以及是否缓存某些属性、缓存多久等等。
Object Name介绍
ObjectName:是MBean的唯一标识,它在MBean向MBean服务器中注册时指定。管理应用可以通过这个标识来寻址MBean。Object Name体现了MBean服务器关于MBean的命名机制,这一机制是管理应用和MBean之间实现松耦合的关键。
Object Name的语法如下:
[domainName]:property=value[,property=value]*
可以看到,Object Name由两部分组成:域名和一组关键属性,具体说明如下。
(1) 域名(Domain Name)
关于域名的命名和Java包的约定一致,即“反向的DNS名 + 组织自定义的字串”。比如由Sun公司开发的MBean,其DNS名是sun.com,则其域名格式是com.sun.MyDomain。
(2) 关键属性(Key Properties)
关键属性是一些Key-value对,通过它们可以为MBean在指定的域中添加包括名字、类型和说明等属性,但这些属性可以不是MBean的实际属性。
例子: MyDomain:description=Printer,type=laser
资料:
- http://download.oracle.com/javase/6/docs/api/javax/management/package-summary.html
- http://ajava.org/readbook/J2EE/glassfish/9793.html
- http://tech.it168.com/a2009/0225/266/000000266836.shtml
标准MBean例子:
1. 定义MBean接口
1.public interface StandardServerMonitorMBean {
2. public long getUpTime();
3. public void start();
4.}
说明:
- MBean的类命名和方法命名上存在一些约定
类命名:需要监控的类名基础上加上"MBean",做为接口名字。对应的监控类必须实现该接口,通过该接口可以表述需要被jmx管理的attribute , operation信息等。
方法名: get/set/is打头的代表的是一个attribute, 其他的一些方法定义做为可被操作的operation。 - 方法名,注意是去掉get/set/is后的name , 注意第一个字母大写。 这里就是UpTime
2. 实现具体的监控类
1.public class StandardServerMonitor implements StandardServerMonitorMBean {
2.
3. public long startTime = 0;
4.
5. public long getUpTime() {
6. return System.currentTimeMillis() - startTime;
7. }
8.
9. @Override
10. public void start() {
11. startTime = System.currentTimeMillis();
12. }
13.
14.}
说明:
- 必须实现 类名+MBean 的一个接口
3. 调用测试
1.StandardServerMonitor serverMonitor = new StandardServerMonitor();
2. // 注册mbean
3. MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer();
4. ObjectName objectName = new ObjectName("objectName: id=serverMonitor");
5. mBeanServer.registerMBean(serverMonitor, objectName);
6. // mbean调用
7. mBeanServer.invoke(objectName, "start", null, null);
8. Thread.sleep(1000);
9. Long upTime = (Long) mBeanServer.getAttribute(objectName, "UpTime");
10. System.out.println("uptime : " + upTime);
输出结果:
1.uptime : 1000
DynamicMBean例子:
1. 实现Dynamic接口
1.public class DynamicServerMonitor implements DynamicMBean {
2.
3. private MBeanInfo mBeanInfo;
4. private StandardServerMonitor monitor;
5.
6. public DynamicServerMonitor(StandardServerMonitor monitor){
7. this.monitor = monitor;
8. }
9.
10. @Override
11. public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
12. if (attribute.equals("UpTime")) {
13. return monitor.getUpTime();
14. }
15. return null;
16. }
17.
18. @Override
19. public AttributeList getAttributes(String[] attributes) {
20. AttributeList result = new AttributeList();
21. for (String attr : attributes) {
22. if (attr.equals("UpTime")) {
23. result.add(monitor.getUpTime());
24. }
25. }
26. return result;
27. }
28.
29. @Override
30. public MBeanInfo getMBeanInfo() {
31. if (mBeanInfo == null) {
32. try {
33. Class cls = StandardServerMonitor.class;
34. // 用反射获得 "upTime" 属性的读方法
35. Method readMethod = cls.getMethod("getUpTime", new Class[0]);
36. // 用反射获得构造方法
37. Constructor constructor = cls.getConstructor();
38. // 关于 "upTime" 属性的元信息:名称为 UpTime,只读属性(没有写方法)。
39. MBeanAttributeInfo upTimeMBeanAttributeInfo = new MBeanAttributeInfo(
40. "UpTime",
41. "The time span since server start",
42. readMethod, null);
43. // 关于构造函数的元信息
44. MBeanConstructorInfo mBeanConstructorInfo = new MBeanConstructorInfo("Constructor for ServerMonitor",
45. constructor);
46. // ServerMonitor 的元信息,为了简单起见,在这个例子里,
47. // 没有提供 invocation 以及 listener 方面的元信息
48. mBeanInfo = new MBeanInfo(cls.getName(), "Monitor that controls the server",
49. new MBeanAttributeInfo[] { upTimeMBeanAttributeInfo },
50. new MBeanConstructorInfo[] { mBeanConstructorInfo }, null, null);
51. } catch (Exception e) {
52. throw new Error(e);
53. }
54.
55. }
56. return mBeanInfo;
57. }
58.
59. @Override
60. public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException,
61. ReflectionException {
62.
63. Class[] parmeterClass = null;
64. if (params != null) {
65. parmeterClass = new Class[params.length];
66. for (int i = 0; i < params.length; i++) {
67. parmeterClass[i] = params[i].getClass();
68. }
69. }
70.
71. try {
72. Method method = StandardServerMonitor.class.getMethod(actionName, parmeterClass);
73. return method.invoke(monitor, params);
74. } catch (Exception e) {
75. e.printStackTrace();
76. }
77.
78. return null;
79. }
80.
81. @Override
82. public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException,
83. MBeanException, ReflectionException {
84.
85. }
86.
87. @Override
88. public AttributeList setAttributes(AttributeList attributes) {
89. return null;
90. }
91.
92.}
说明: 需要实现getAttribute/setAttribute的方法,包括invoke方法。 自己实现相应的监控方法路由
2. 调用例子
1.StandardServerMonitor serviceMonitor = new StandardServerMonitor();
2. DynamicServerMonitor dynamicServerMonitor = new DynamicServerMonitor(serviceMonitor);
3. // 注册mbean
4. MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer();
5. ObjectName objectName = new ObjectName("objectName:id=dynamicServerMonitor");
6. mBeanServer.registerMBean(dynamicServerMonitor, objectName);
7. // mbean调用
8. mBeanServer.invoke(objectName, "start", null, null);
9. Thread.sleep(1000);
10. Long upTime = (Long) mBeanServer.getAttribute(objectName, "UpTime");
11. System.out.println("uptime : " + upTime);
java.lang.management系列
jvm 1.5之后默认提供了一些MBean,用于管理jvm资源,具体的MBean如下:
Object Name | MXBean | 方法描述 |
java.lang:type=ClassLoading | ClassLoadingMXBean | 包括一些类的装载信息,比如有多少类已经装载/卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java –verbose:class 选项)是否打开,还可以帮助用户打开/关闭该选项。 |
java.lang:type=Compilation | CompilationMXBean | 帮助用户了解当前的编译器和编译情况 |
java.lang:type=Memory | MemoryMXBean | 提供了整个虚拟机中内存的使用情况,包括 Java 堆(heap)和非 Java 堆所占用的内存,提供当前等待 finalize 的对象数量,它甚至可以做 gc(实际上是调用 System.gc) |
java.lang:type=OperatingSystem | OperatingSystemMXBean | 该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等 |
java.lang:type=Runtime | RuntimeMXBean | 运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等 |
java.lang:type=Threading | ThreadMXBean | 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息 |
java.lang:type=GarbageCollector | GarbageCollectorMXBean | 仅仅提供了 GC 的次数和 GC 花费总时间的近似值 |
java.lang:type=MemoryManager | MemoryManagerMXBean | 提供了内存管理类和内存池(memory pool)的名字信息 |
java.lang:type=MemoryPool | MemoryPoolMXBean | 在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含了该内存池的详细信息,如是否可用、当前已使用内存/最大使用内存值、以及设置最大内存值等等 |
说明:
1. 通过MemoryMXBean ,可以实现内存阀值控制,比如自定义一个javax.management.NotificationListener,在内存低于MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED,进行消息提醒,邮件或者短信等
2. 通过ThreadMXBean ,可以通过getLockedMonitors(),getLockedSynchronizers(),getLockInfo()获取锁信息,通过findDeadlockedThreads()检测死锁
最后
简单的整理下jmx的相关知识,可以做为入门教程。 线上的一些监控可以通过jmx进行监控处理,做为了解还是不错的