jmx监控tomcat
一、环境:
1、监控端client:macOS
2、被监控端server:系统Ubuntu16.0.4,tomcat8
二、步骤:
1、修改文件配置tomcat/bin/catalina.sh
在文件开头的一大段注释下添加以下内容:
CATALINA_OPTS=”$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -Djava.rmi.server.hostname=192.168.31.187”
这其中-Dcom.sun.management.jmxremote.port=8999 设置端口号
-Dcom.sun.management.jmxremote.ssl=false 不使用ssl安全认证
-Dcom.sun.management.jmxremote.authenticate=true 设置用户名和密码认证
-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password 用户和密码文件
-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access 权限文件
-Djava.rmi.server.hostname=192.168.31.187”设置本机的ip(不设置的话client请求到本机本机会返回一个hostname对象,client再请求本机hostname对应的ip,参考http://blog.csdn.net/yangyan19870319/article/details/6732411)
2、复制java/jdk/jre/lib/management/下的jmxremote.access、jmxremote.password.template文件到/tomcat/conf/下
(1)把jmxremote.password.template重命名为jmxremote.password,
修改两个文件的权限:
chmod 600 jmxremote.access
chmod 600 jmxremote.password
(2)设置用户权限,在jmxremote.access里的最后面添加(没有则添加)如下内容:
monitorRole readonly
controlRole readwrite \
create javax.management.monitor.,javax.management.timer. \
unregister
(3)编辑最后的账户密码,在jmxremote.password.里的最后面添加(没有则添加)如下内容:
monitorRole mj #密码可以随便取
controlRole mj #密码可以随便取
3、到tomcat/bin下用 ./shutdown.sh和./start.sh来测试是否能正常启动和关闭tomcat,若不能则配置错误;
4、启动tomcat,用netstat –ntlp
看得刚才配置8999端口,证明成功一半了。
5、监控端连接tomcat的代码:
package jmx;
import java.lang.management.MemoryUsage;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class tomcat {
private static Formatter format = new Formatter();
public static void main(String[] args) throws Exception {
String jmxURL = "service:jmx:rmi:///jndi/rmi://192.168.31.133:8999/jmxrmi";
JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);
Map map = new HashMap();
// 用户名密码,在jmxremote.password文件中查看
String[] credentials = new String[] { "monitorRole", "QED" };
map.put("jmx.remote.credentials", credentials);
JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map);
// JMXConnector connector = JMXConnectorFactory.connect(serviceURL, null);
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
// 端口最好是动态取得
ObjectName grpObjName = new ObjectName("Catalina:type=GlobalRequestProcessor,*");
Set<ObjectName> grps = mbsc.queryNames(grpObjName, null);
for (ObjectName obj : grps) {
System.out.println("名称:" + obj.getKeyProperty("name"));
ObjectName objname = new ObjectName(obj.getCanonicalName());
System.out.println("bytesReceived:" + mbsc.getAttribute(objname, "bytesReceived"));
System.out.println("bytesSent:" + mbsc.getAttribute(objname, "bytesSent"));
System.out.println("requestCount:" + mbsc.getAttribute(objname, "requestCount"));
}
//线程池
ObjectName threadObjName = new ObjectName("Catalina:type=ThreadPool,name=\"*http*\"");
Set<ObjectName> smbi = mbsc.queryNames(threadObjName, null);
for (ObjectName obj : smbi) {
System.out.println("端口名:" + obj.getKeyProperty("name"));
ObjectName objname = new ObjectName(obj.getCanonicalName());
System.out.println("最大线程数:" + mbsc.getAttribute(objname, "maxThreads"));
System.out.println("当前线程数:" + mbsc.getAttribute(objname, "currentThreadCount"));
System.out.println("繁忙线程数:" + mbsc.getAttribute(objname, "currentThreadsBusy"));
}
// ------------------------ system ----------------------
ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime");
System.out.println("厂商:" + (String) mbsc.getAttribute(runtimeObjName, "VmVendor"));
System.out.println("程序:" + (String) mbsc.getAttribute(runtimeObjName, "VmName"));
System.out.println("版本:" + (String) mbsc.getAttribute(runtimeObjName, "VmVersion"));
Date starttime = new Date((Long) mbsc.getAttribute(runtimeObjName, "StartTime"));
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("启动时间:" + df.format(starttime));
Long timespan = (Long) mbsc.getAttribute(runtimeObjName, "Uptime");
System.out.println("连续工作时间:" + tomcat.formatTimeSpan(timespan));
// 堆使用率
ObjectName heapObjName = new ObjectName("java.lang:type=Memory");
MemoryUsage heapMemoryUsage = MemoryUsage
.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "HeapMemoryUsage"));
long maxMemory = heapMemoryUsage.getMax();// 堆最大
System.out.println("heap size:" + maxMemory);
long commitMemory = heapMemoryUsage.getCommitted();// 堆当前分配
long usedMemory = heapMemoryUsage.getUsed();
System.out.println("heap:" + (double) usedMemory * 100 / commitMemory + "%");// 堆使用率
MemoryUsage nonheapMemoryUsage = MemoryUsage
.from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "NonHeapMemoryUsage"));
long noncommitMemory = nonheapMemoryUsage.getCommitted();
long nonusedMemory = heapMemoryUsage.getUsed();
System.out.println("nonheap:" + (double) nonusedMemory * 100 / noncommitMemory + "%");
ObjectName permObjName = new ObjectName("java.lang:type=MemoryPool,name=*Perm*Gen*");
Set<ObjectName> sperm = mbsc.queryNames(permObjName, null);
for (ObjectName obj : sperm) {
ObjectName objname = new ObjectName(obj.getCanonicalName());
MemoryUsage permGenUsage = MemoryUsage.from((CompositeDataSupport) mbsc.getAttribute(objname, "Usage"));
long committed = permGenUsage.getCommitted();// 持久堆大小
long used = heapMemoryUsage.getUsed();//
System.out.println("perm gen:" + (double) used * 100 / committed + "%");// 持久堆使用率
}
}
public static String formatTimeSpan(long span) {
long minseconds = span % 1000;
span = span / 1000;
long seconds = span % 60;
span = span / 60;
long mins = span % 60;
span = span / 60;
long hours = span % 24;
span = span / 24;
long days = span;
return format.format("%1$d天 %2$02d:%3$02d:%4$02d.%5$03d", days, hours, mins, seconds, minseconds).toString();
}
}
6、运行代码如果以下错误
原因是:除了JMX server指定的监听端口号外,JMXserver还会监听一到两个随机端口号,
绿色线两个端口就是随机端口(pid跟8999端口的pid一样)。
解决方法有两种:
第一种:关闭防火墙
第二种:每次启动java进程后查看这两个随机端口然后添加这两个端口到防火墙配置(最好的方法是用脚本获取两个随机端口然后修改防火墙配置并重启防火墙)