JMX-JAVA进程监控利器
来源:互联网 发布:不能安装淘宝助理 编辑:程序博客网 时间:2024/06/01 12:59
Java 管理扩展(Java Management Extension,JMX)是从jdk1.4开始的,但从1.5时才加到jdk里面,并把API放到java.lang.management包里面。
如果一个 Java 对象可以由一个遵循 JMX 规范的管理器应用管理,那么这个Java 对象就可以称为一个可由 JMX 管理的资源。
要使一个 Java 对象可管理,则必须创建相应的 MBean 对象,并通过这些 MBean 对象管理相应的 Java 对象。当拥有 MBean 类后,需要将其实例化并注册到 MBeanServer 上。
一共有四种类型的 MBean , 分别是标准类型 MBean, 动态类型 MBean, 开放类型 MBean 和模型类型 MBean。
注:
- 一个java进程里面可以有多个不同名字的mBeanServer ,每个mbs都是一个独立的容器,用了管理mbean
- 每个mbs都可以注册多个rmi port,http port等
- platformMBeanServer 是由jvm创建的,并添加了一些系统的mbean,如cpu,内存,网络,线程等等
1、本机使用
当我们启动java进程后,经常会使用jps,jinfo,jmap,jstat等jdk自带的命令去查询进程的状态,这其中的原理就是,当java进程启动后,会创建一个用于本机连接的“localConnectorAddress”放到当前用户目录下,当使用jps等连接时,会到当前用户目录下取到“localConnectorAddress”并连接。
@Testpublic void test1() {List<VirtualMachineDescriptor> vms = VirtualMachine.list();for (VirtualMachineDescriptor desc : vms) {VirtualMachine vm;try {System.out.println("desc:" + desc);System.out.println("进程id:"+desc.id());vm = VirtualMachine.attach(desc);} catch (Exception e) {e.printStackTrace();continue;}JMXConnector connector = null;try {Properties props = vm.getAgentProperties();for (Map.Entry<Object, Object> entry : props.entrySet()) {System.out.println(entry.getKey() + "->" + entry.getValue());}String connectorAddress = props.getProperty("com.sun.management.jmxremote.localConnectorAddress");if (connectorAddress == null) {System.out.println("connectorAddress is null");continue;}System.out.println("conn:" + connectorAddress); //以下代码用于连接指定的jmx,本地或者远程JMXServiceURL url = new JMXServiceURL(connectorAddress);//JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/TestJMXServer"); connector = JMXConnectorFactory.connect(url);MBeanServerConnection mbeanConn = connector.getMBeanServerConnection();Set<ObjectName> beanSet = mbeanConn.queryNames(null, null);// ...} catch (Exception e) {e.printStackTrace();} finally {try {if (connector != null) connector.close();break;} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
需要注意的是,上面代码需要把tools.jar放到classpath里面。
上面代码有时候取不到本地连接地址,这个时候需要尝试让agent加载management-agent.jar,完整代码如下:
package cn.myroute.mbean;import java.io.File;import java.io.IOException;import java.lang.reflect.Method;import java.net.URL;import java.net.URLClassLoader;import java.util.List;import java.util.Properties;public class AbstractJmxCommand { private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; public static String getJVM() { return System.getProperty("java.vm.specification.vendor"); } public static boolean isSunJVM() { // need to check for Oracle as that is the name for Java7 onwards. return getJVM().equals("Sun Microsystems Inc.") || getJVM().startsWith("Oracle"); } public static void main(String[] args) {if (args == null || args.length == 0) {System.out.println("Usage: pid");return;}int pid =Integer.valueOf(args[0]);System.out.println(new AbstractJmxCommand().findJMXUrlByProcessId(pid));} /** * Finds the JMX Url for a VM by its process id * * @param pid * The process id value of the VM to search for. * * @return the JMX Url of the VM with the given pid or null if not found. */ // @SuppressWarnings({ "rawtypes", "unchecked" }) protected String findJMXUrlByProcessId(int pid) { if (isSunJVM()) { try { // Classes are all dynamically loaded, since they are specific to Sun VM // if it fails for any reason default jmx url will be used // tools.jar are not always included used by default class loader, so we // will try to use custom loader that will try to load tools.jar String javaHome = System.getProperty("java.home"); String tools = javaHome + File.separator + ".." + File.separator + "lib" + File.separator + "tools.jar"; URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()}); Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader); Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true, loader); Method getVMList = virtualMachine.getMethod("list", (Class[])null); Method attachToVM = virtualMachine.getMethod("attach", String.class); Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[])null); Method getVMId = virtualMachineDescriptor.getMethod("id", (Class[])null); List allVMs = (List)getVMList.invoke(null, (Object[])null); for(Object vmInstance : allVMs) { String id = (String)getVMId.invoke(vmInstance, (Object[])null); if (id.equals(Integer.toString(pid))) { Object vm = attachToVM.invoke(null, id); Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null); String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS); if (connectorAddress != null) { return connectorAddress; } else { break; } } } //上面的尝试都不成功,则尝试让agent加载management-agent.jar Method getSystemProperties = virtualMachine.getMethod("getSystemProperties", (Class[])null); Method loadAgent = virtualMachine.getMethod("loadAgent", String.class, String.class); Method detach = virtualMachine.getMethod("detach", (Class[])null); for(Object vmInstance : allVMs) { String id = (String)getVMId.invoke(vmInstance, (Object[])null); if (id.equals(Integer.toString(pid))) { Object vm = attachToVM.invoke(null, id); Properties systemProperties = (Properties)getSystemProperties.invoke(vm, (Object[])null); String home = systemProperties.getProperty("java.home"); // Normally in ${java.home}/jre/lib/management-agent.jar but might // be in ${java.home}/lib in build environments. String agent = home + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar"; File f = new File(agent); if (!f.exists()) { agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; f = new File(agent); if (!f.exists()) { throw new IOException("Management agent not found"); } } agent = f.getCanonicalPath(); loadAgent.invoke(vm, agent, "com.sun.management.jmxremote"); Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null); String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS); //detach 这个vm detach.invoke(vm, (Object[])null); if (connectorAddress != null) { return connectorAddress; } else { break; } } } } catch (Exception ignore) { ignore.printStackTrace(); } } return null; }}
2、远程连接
2.1 rmi端口注册及访问
2.1.1 直接在代码里面绑定端口
@Testpublic void testJmxRmiRegist() throws Exception {int rmiPort = 2222;String jmxServerName = "cn.myroute.mbean.mm";// jdkfolder/bin/rmiregistry.exe 9999Registry registry = LocateRegistry.createRegistry(rmiPort);MBeanServer mbs = MBeanServerFactory.createMBeanServer(jmxServerName);System.out.println(mbs);// mbs = MBeanServerFactory.createMBeanServer();// 新建MBean ObjectName, 在MBeanServer里标识注册的MBeanObjectName name = new ObjectName(jmxServerName + ":type=Echo");// HtmlAdaptorServer adapter = new HtmlAdaptorServer();// 创建MBeanEcho mbean = new Echo();// 在MBeanServer里注册MBean, 标识为ObjectName(com.tenpay.jmx:type=Echo)mbs.registerMBean(mbean, name);JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + rmiPort + "/" + jmxServerName);System.out.println("JMXServiceURL: " + url.toString());JMXConnectorServer jmxConnServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);jmxConnServer.start();Thread.sleep(1000 * 60 * 10);}
上面程序是新建了个mbeanserver,并通过rmi绑定到2222端口上,等待客户端连接。
2.1.2 通过jmx参数启动进程
2.2通过http访问
@Testpublic void testJmxHtmlAdapter() throws Exception {String jmxServerName = "cn.myroute.mbean.mm";// jdkfolder/bin/rmiregistry.exe 9999MBeanServer mbs = MBeanServerFactory.createMBeanServer(jmxServerName);System.out.println(mbs);// mbs = MBeanServerFactory.createMBeanServer();// 新建MBean ObjectName, 在MBeanServer里标识注册的MBeanObjectName name = new ObjectName(jmxServerName + ":type=Echo");// HtmlAdaptorServer adapter = new HtmlAdaptorServer();// 创建MBeanEcho mbean = new Echo();// 在MBeanServer里注册MBean, 标识为ObjectName(com.tenpay.jmx:type=Echo)mbs.registerMBean(mbean, name); HtmlAdaptorServer adapter = new HtmlAdaptorServer(); ObjectName adapterName; adapterName = new ObjectName(jmxServerName + ":name=" + "htmladapter"); adapter.setPort(8082); adapter.start(); mbs.registerMBean(adapter, adapterName); Thread.sleep(1000 * 60 * 10);}
以上代码用到了HtmlAdaptorServer,需要下载jjmx-1_2_1-ri.zip,把里面的jmxtools.jar加的classpath里面,下载地址:http://java.sun.com/products/JavaManagement/download.html。
3、客户端连接
@Testpublic void test1() {try {JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:2222/cn.myroute.mbean.mm");JMXConnector connector = JMXConnectorFactory.connect(url);MBeanServerConnection mbeanConn = connector.getMBeanServerConnection();Set<ObjectName> beanSet = mbeanConn.queryNames(null, null);System.out.println(beanSet);}catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
4、java进程自带的mbean
- ClassLoadingMXBean
ClassLoadMXBean 包括一些类的装载信息,比如有多少类已经装载 / 卸载(unloaded),虚拟机类装载的 verbose 选项(即命令行中的 Java – verbose:class 选项)是否打开,还可以帮助用户打开 / 关闭该选项。
- CompilationMXBean
CompilationMXBean 帮助用户了解当前的编译器和编译情况,该 mxbean 提供的信息不多。
- GarbageCollectorMXBean
相对于开放人员对 GC 的关注程度来说,该 mxbean 提供的信息十分有限,仅仅提供了 GC 的次数和 GC 花费总时间的近似值。但是这个包中还提供了三个的内存管理检测类:MemoryManagerMXBean,MemoryMXBean 和 MemoryPoolMXBean。
- MemoryManagerMXBean
这个类相对简单,提供了内存管理类和内存池(memory pool)的名字信息。
- MemoryMXBean
这个类提供了整个虚拟机中内存的使用情况,包括 Java 堆(heap)和非 Java 堆所占用的内存,提供当前等待 finalize 的对象数量,它甚至可以做 gc(实际上是调用 System.gc)。
- MemoryPoolMXBean
该信息提供了大量的信息。在 JVM 中,可能有几个内存池,因此有对应的内存池信息,因此,在工厂类中,getMemoryPoolMXBean() 得到是一个 MemoryPoolMXBean 的 list。每一个 MemoryPoolMXBean 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。
- MemoryManagerMXBean
- OperatingSystemMXBean
该类提供的是操作系统的简单信息,如构架名称、当前 CPU 数、最近系统负载等。
- RuntimeMXBean
运行时信息包括当前虚拟机的名称、提供商、版本号,以及 classpath、bootclasspath 和系统参数等等。
- ThreadMXBean
在 Java 这个多线程的系统中,对线程的监控是相当重要的。ThreadMXBean 就是起到这个作用。ThreadMXBean 可以提供的信息包括各个线程的各种状态,CPU 占用情况,以及整个系统中的线程状况。从 ThreadMXBean 可以得到某一个线程的 ThreadInfo 对象。这个对象中则包含了这个线程的所有信息。
java.lang.management.ManagementFactory
这个工厂类来获得一系列的 MXBean。ClassLoadingMXBean mbs = ManagementFactory.getClassLoadingMXBean();System.out.println("loadedClass:" + mbs.getLoadedClassCount());
- JMX-JAVA进程监控利器
- Java监控activeMQ(JMX)
- JAVA技术提高(JMX监控)
- jmx 监控
- 利用JMX来监控大部分java应用
- JMX监控Zookeeper状态Java API
- 利用JMX来监控大部分java应用
- zabbix 监控jmx 需要--enable-java
- jmx配合jvisualvm远程监控Java程序
- 利用JMX来监控大部分java应用
- Java操作 ActiveMQ 远程监控JMX设置
- JMX监控Zookeeper状态Java API
- Java操作 ActiveMQ 远程监控JMX设置
- 添加jstatd、jmx启动远程java监控或tomcat监控
- 进程监控程序-java
- 远程监控Java进程
- Jenkins java进程监控
- JMX配置Tomcat 7.0连接Linux java监控
- design pattern
- android 创建简单通用工程
- 使用android创建安卓项目工程或者创建安卓测试项目工程命令详解
- 六、类和对象
- IDEA导入web项目时Tomcat的配置
- JMX-JAVA进程监控利器
- 跳坑(2)
- 跨域 - JSONP
- servlet中使用MD5
- 古墓丽影9
- 判断当前是哪一个活动
- NodeJS学习笔记
- Java条件语句之 switch
- ThinkPHP3.2的Excel导入