当前位置: 首页 > news >正文

jmx编程监控mysql_JMX-JAVA进程监控利器

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。

98e40f0b2afbb61001ced67984cdd88c.png

注:

一个java进程里面可以有多个不同名字的mBeanServer ,每个mbs都是一个独立的容器,用了管理mbean

每个mbs都可以注册多个rmi port,http port等

platformMBeanServer 是由jvm创建的,并添加了一些系统的mbean,如cpu,内存,网络,线程等等

1、本机使用

当我们启动java进程后,经常会使用jps,jinfo,jmap,jstat等jdk自带的命令去查询进程的状态,这其中的原理就是,当java进程启动后,会创建一个用于本机连接的“localConnectorAddress”放到当前用户目录下,当使用jps等连接时,会到当前用户目录下取到“localConnectorAddress”并连接。

packagecom.dxz.study;importjava.io.IOException;importjava.util.List;importjava.util.Map;importjava.util.Properties;importjava.util.Set;importjavax.management.MBeanServerConnection;importjavax.management.ObjectName;importjavax.management.remote.JMXConnector;importjavax.management.remote.JMXConnectorFactory;importjavax.management.remote.JMXServiceURL;importorg.junit.Test;importcom.sun.tools.attach.VirtualMachine;importcom.sun.tools.attach.VirtualMachineDescriptor;public classJmxTest {

@Testpublic voidtest1() {

List 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.Entryentry : 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 = newJMXServiceURL(connectorAddress);//JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/TestJMXServer");

connector =JMXConnectorFactory.connect(url);

MBeanServerConnection mbeanConn=connector.getMBeanServerConnection();

Set 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 block

e.printStackTrace();

}

}

}

}

}

pom.xml

4.0.0

com.dxz

study

0.0.1-SNAPSHOT

jar

study

http://maven.apache.org

UTF-8

junit

junit

4.1

test

org.glassfish.external

opendmk_jdmkrt_jar

1.0-b01-ea

org.jmockit

jmockit

1.24

上面代码有时候取不到本地连接地址,这个时候需要尝试让agent加载management-agent.jar,完整代码如下:

packagecom.dxz.study;importjava.io.File;importjava.io.IOException;importjava.lang.reflect.Method;importjava.net.URL;importjava.net.URLClassLoader;importjava.util.List;importjava.util.Properties;public classAbstractJmxCommand {private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress";public staticString getJVM() {return System.getProperty("java.vm.specification.vendor");

}public static booleanisSunJVM() {//need to check for Oracle as that is the name for Java7 onwards.

return getJVM().equals("Sun Microsystems Inc.") || getJVM().startsWith("Oracle");

}public static voidmain(String[] args) {if (args == null || args.length == 0) {

System.out.println("Usage: pid");return;

}int pid = Integer.valueOf(args[0]);

System.out.println(newAbstractJmxCommand().findJMXUrlByProcessId(pid));

}/*** Finds the JMX Url for a VM by its process id

*

*@parampid

* The process id value of the VM to search for.

*

*@returnthe JMX Url of the VM with the given pid or null if not found.*/

//@SuppressWarnings({ "rawtypes", "unchecked" })

protected String findJMXUrlByProcessId(intpid) {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[] { newFile(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) {returnconnectorAddress;

}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= newFile(agent);if (!f.exists()) {

agent= home + File.separator + "lib" + File.separator + "management-agent.jar";

f= newFile(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) {returnconnectorAddress;

}else{break;

}

}

}

}catch(Exception ignore) {

ignore.printStackTrace();

}

}return null;

}

}

2、远程连接

毫无疑问,若想远程连接访问,肯定需要mBeanServer注册一个或多个端口,如rmi端口,http端口等。

2.1 rmi端口注册及访问

有两种方法,一种直接在代码里面指定rmi端口,并绑定,如下,此种方法需要使用客户端连接代码访问,另一种代码不用指定端口,之需把mbean注册到platformMBeanServer 里面,并在启动进程时加jmx参数指定,用这种方法可以通过jconsole,jvisualvm远程访问。

2.1.1 直接在代码里面绑定端口

@Testpublic void testJmxRmiRegist() throwsException {int rmiPort = 2222;

String jmxServerName= "com.dxz.study.TestJmxRmiRegist";//jdkfolder/bin/rmiregistry.exe 9999

Registry registry =LocateRegistry.createRegistry(rmiPort);

MBeanServer mbs=MBeanServerFactory.createMBeanServer(jmxServerName);

System.out.println(mbs);//mbs = MBeanServerFactory.createMBeanServer();//新建MBean ObjectName, 在MBeanServer里标识注册的MBean

ObjectName name = new ObjectName(jmxServerName + ":type=HelloWorld");//HtmlAdaptorServer adapter = new HtmlAdaptorServer();//在MBeanServer里注册MBean, 标识为ObjectName(com.tenpay.jmx:type=Echo)

mbs.registerMBean(newHelloWorld(), 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参数启动进程

#JVMARGS="$JVMARGS -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"

通过这种把进程的jmx监控绑定指定的端口,即可在远端通过jconsole进行监控。

2.2通过http访问

@Testpublic void testJmxHtmlAdapter() throwsException {

String jmxServerName= "com.dxz.study.TestJmxRmiRegist";//jdkfolder/bin/rmiregistry.exe 9999

MBeanServer mbs=MBeanServerFactory.createMBeanServer(jmxServerName);

System.out.println(mbs);//mbs = MBeanServerFactory.createMBeanServer();//新建MBean ObjectName, 在MBeanServer里标识注册的MBean

ObjectName name = new ObjectName(jmxServerName + ":type=HelloWorld");//HtmlAdaptorServer adapter = new HtmlAdaptorServer();//创建MBean//在MBeanServer里注册MBean, 标识为ObjectName(com.tenpay.jmx:type=Echo)

mbs.registerMBean(newHelloWorld(), name);

HtmlAdaptorServer adapter= newHtmlAdaptorServer();

ObjectName adapterName;

adapterName= new ObjectName(jmxServerName + ":name=" + "htmladapter");

adapter.setPort(8082);

adapter.start();

mbs.registerMBean(adapter, adapterName);

Thread.sleep(1000 * 60 * 10);

}

以上代码用到了HtmlAdaptorServer,

org.glassfish.external

opendmk_jdmkrt_jar

1.0-b01-ea

然后用浏览器访问即可

9d7ceb0ccf3e0e51b4aa054f96f622c7.png

3、客户端连接

packagecom.dxz.study;importjava.util.Set;importjavax.management.MBeanServerConnection;importjavax.management.ObjectName;importjavax.management.remote.JMXConnector;importjavax.management.remote.JMXConnectorFactory;importjavax.management.remote.JMXServiceURL;importorg.junit.Test;public classJmxClientTest {

@Testpublic voidtest1() {try{

JMXServiceURL url= new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:2222/com.dxz.study.TestJmxRmiRegist");

JMXConnector connector=JMXConnectorFactory.connect(url);

MBeanServerConnection mbeanConn=connector.getMBeanServerConnection();

Set beanSet = mbeanConn.queryNames(null, null);

System.out.println(beanSet);

}catch(Exception e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

结果:

[com.dxz.study.TestJmxRmiRegist:type=HelloWorld, JMImplementation:type=MBeanServerDelegate]

4、jconsole连接(待验证)

1eeb6601a994e3af34c524ccda4f42d0.png

5、java进程自带的mbean

当我们在用jconsole、jvisualvm进行监控java进程时,通常都能看到cpu、内存、线程、垃圾收集等使用情况,其实数据都是通过jmx从jvm提供的一些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 都包含了该内存池的详细信息,如是否可用、当前已使用内存 / 最大使用内存值、以及设置最大内存值等等。

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());

相关文章:

  • zookeeper清空hbase_zookeeper和HBASE总结
  • ldap radius mysql_OpenLDAP+FreeRADIUS+MySQL+RP-PPPOE 构建PPPOE服务器
  • mysql分批导出数据_一分钟学会系列:大批量数据导出Excel-分页查询性能优化
  • php mysql 创建数据表_PHP MySQL 创建数据表
  • pythonioerror0 121_Python中的“IOError:[Errno 0]Error”错误
  • python词云乱码_python词云库wordCloud使用方法详解(解决中文乱码)
  • 儿童手工制作日历_怎么做手工儿童卡通绵羊日程管理小日历
  • 内存cpu占用不高但mysql很卡_解决Mysql占用cpu,内存高故障案例
  • 康乐面板mysql默认密码_Linux安装kangle(康乐)网站管理面板的详细教程
  • mysql jpa 不要自动建表_18.1. 从零开始学springboot-配置jpa自动建表为innodb
  • mysql 存储json如何查出_Mysql如何提取存储的JSON值
  • mysql增量备份backupex_数据库增量备份,恢复innobackex
  • python如何剪辑音频_剪辑音乐要很久?3行语句Python瞬间搞定
  • tomcat文件路径更换_tomcat图片上传指定位置并显示(修改配置文件)
  • 小程序在输入npm命令_【微信小程序】使用npm包-傻瓜式教程
  • 【Leetcode】101. 对称二叉树
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 77. Combinations
  • Apache的80端口被占用以及访问时报错403
  • CSS中外联样式表代表的含义
  • ES6 ...操作符
  • JavaScript标准库系列——Math对象和Date对象(二)
  • JS函数式编程 数组部分风格 ES6版
  • magento2项目上线注意事项
  • node-glob通配符
  • python学习笔记 - ThreadLocal
  • React+TypeScript入门
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • unity如何实现一个固定宽度的orthagraphic相机
  • 给Prometheus造假数据的方法
  • 微信公众号开发小记——5.python微信红包
  • 移动端解决方案学习记录
  • 栈实现走出迷宫(C++)
  • 7行Python代码的人脸识别
  • linux 淘宝开源监控工具tsar
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (52)只出现一次的数字III
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (附源码)php新闻发布平台 毕业设计 141646
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (原)本想说脏话,奈何已放下
  • (转)iOS字体
  • (转)linux 命令大全
  • *2 echo、printf、mkdir命令的应用
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Core 中的路径问题
  • .net core使用ef 6
  • .NET 反射的使用
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET开发不可不知、不可不用的辅助类(一)
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • 。Net下Windows服务程序开发疑惑
  • @WebService和@WebMethod注解的用法