监控应用服务器使用JMX监控Tomcat (推荐)


前言:做了一个监控应用服务器的项目(支持Tocmat、WebSphere、WebLogic各版本), 过程也算是磕磕绊绊,由于网上缺少相关资料,或者深陷于知识的海洋难以寻觅到有效的资料,因而走过不少弯路,遇过不少困难。为了留下点印记,给后来人留下 点经验之谈,助之少走弯路,故将这些经验整理出来,与大家分享。水平有限,难免疏漏,还望指正。如有疑问,欢迎留言,或者加入Q群参与讨 论:35526521。

一、激活Tomcat的JMX远程配置

要通过JMX远程监控Tomcat,首先需要激活Tomcat的JMX远程配置。

① 先修改Tomcat的启动脚本,windows下为bin/catalina.bat(linux下为catalina.sh),添加以下内容,8999是jmxremote使用的端口号,第二个false表示不需要鉴权:
Xml代码 

set JMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote 
  -Dcom.sun.management.jmxremote.port=8999
  -Dcom.sun.management.jmxremote.ssl=false
  -Dcom.sun.management.jmxremote.authenticate=false set CATALINA_OPTS=%CATALINA_OPTS% %JMX_REMOTE_CONFIG%

要注意以上语句的位置不能太后面,可以加在【if "%OS%" == "Windows_NT" setlocal】一句后的大段的注释后面。

参考官方说明:
http://tomcat.apache.org/tomcat-6.0-doc/monitoring.html#Enabling_JMX_Remote


② 上面的配置是不需要鉴权的,如果需要鉴权则添加的内容为:
Xml代码 

set JMX_REMOTE_CONFIG=-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 set CATALINA_OPTS=%CATALINA_OPTS% %JMX_REMOTE_CONFIG%


③ 然后复制并修改授权文件
$JAVA_HOME/jre/lib/management下有jmxremote.access和jmxremote.password的模板文件,将两个文件复制到$CATALINA_BASE/conf目录下
◆ 修改$CATALINA_BASE/conf/jmxremote.access 添加内容:

     monitorRole readonly
     controlRole readwrite 

 


◆ 修改$CATALINA_BASE/conf/jmxremote.password 添加内容:

     monitorRole tomcat
     controlRole tomcat


注意: 如果进行了以上步骤导致Tomcat启动不了,那么很可能是密码文件的权限问题

需要修改jmxremote.password文件的访问权限,只有文件的owner所有者才能拥有访问权限 (并且文件的所有者必须与tomcat的所有者是同一用户):
      Windows的NTFS文件系统下,选中文件,点右键 -->“属性”-->“安全”--> 点“高级”--> 点“更改权限”--> 去掉“从父项继承....”--> 弹出窗口中选“删除”,这样就删除了所有访问权限。再选“添加”--> “高级”--> “立即查找”,选中你的用户(或用户组,如果选用户不行那就选用户组),点“确定",“确定"。来到权限项目窗口,勾选 “完全控制”,点“确定”,OK了。

官方的提示:
      The password file should be read-only and only accessible by the operating system user Tomcat is running as.

④ 重新启动Tomcat,在Windows命令行输入“netstat -a”查看配置的端口号是否已打开,如果打开,说明上面的配置成功了。

⑤ 使用jconsole测试JMX。
运行$JAVA_HOME/bin目录下的jconsole.exe,打开J2SE监视和管理控制台,然后建立连接,如果是本地的Tomcat则 直接选择然后点击连接,如果是远程的,则进入远程选项卡,填写地址、端口号、用户名、口令即可连接。。Mbean属性页中给出了相应的数 据,Catalina中是tomcat的,java.lang是jvm的。对于加粗的黑体属性值,需双击一下才可看内容。


二、使用JMX监控Tomcat示例代码
Java代码 

 1 String jmxURL = "service:jmx:rmi:///jndi/rmi://192.168.10.93:8999/jmxrmi"; 
 2 JMXServiceURL serviceURL = new JMXServiceURL(jmxURL); 
 3  
 4 Map map = new HashMap(); 
 5 // 用户名密码,在jmxremote.password文件中查看 
 6 String[] credentials = new String[] { "monitorRole", "tomcat" }; 
 7 map.put("jmx.remote.credentials", credentials); 
 8 JMXConnector connector = JMXConnectorFactory.connect(serviceURL, map); 
 9 MBeanServerConnection mbsc = connector.getMBeanServerConnection(); 
10  
11 // 端口最好是动态取得 name对应的是ThreadPool 的名称,会有变化,根据自己的设置修改
12 ObjectName threadObjName = new ObjectName("Catalina:type=ThreadPool,name=http-8080"); 
13 MBeanInfo mbInfo = mbsc.getMBeanInfo(threadObjName); 
14  
15 // tomcat的线程数对应的属性值 
16 String attrName = "currentThreadCount"; 
17 MBeanAttributeInfo[] mbAttributes = mbInfo.getAttributes(); 
18 System.out.println("currentThreadCount:" + mbsc.getAttribute(threadObjName, attrName)); 


三、完整的示例代码文件
Java代码 

  1 import java.lang.management.MemoryUsage; 
  2 import java.text.SimpleDateFormat; 
  3 import java.util.Date; 
  4 import java.util.Formatter; 
  5 import java.util.HashMap; 
  6 import java.util.Iterator; 
  7 import java.util.Map; 
  8 import java.util.Set; 
  9  
 10 import javax.management.MBeanAttributeInfo; 
 11 import javax.management.MBeanInfo; 
 12 import javax.management.MBeanServerConnection; 
 13 import javax.management.ObjectInstance; 
 14 import javax.management.ObjectName; 
 15 import javax.management.openmbean.CompositeDataSupport; 
 16 import javax.management.remote.JMXConnector; 
 17 import javax.management.remote.JMXConnectorFactory; 
 18 import javax.management.remote.JMXServiceURL; 
 19  
 20 public class JMXTest { 
 21  
 22     /**
 23      * @param args
 24      */ 
 25     public static void main(String[] args) { 
 26         try { 
 27  
 28             String jmxURL = "service:jmx:rmi:///jndi/rmi://127.0.0.1:8999/jmxrmi"; 
 29  
 30             JMXServiceURL serviceURL = new JMXServiceURL(jmxURL); 
 31  
 32             Map map = new HashMap(); 
 33             String[] credentials = new String[] { "monitorRole", "tomcat" }; 
 34             map.put("jmx.remote.credentials", credentials); 
 35             JMXConnector connector = JMXConnectorFactory.connect(serviceURL, 
 36                     map); 
 37             MBeanServerConnection mbsc = connector.getMBeanServerConnection(); 
 38  
 39             // 端口最好是动态取得 
 40             ObjectName threadObjName = new ObjectName( 
 41                     "Catalina:type=ThreadPool,name=http-8080"); 
 42             MBeanInfo mbInfo = mbsc.getMBeanInfo(threadObjName); 
 43  
 44             String attrName = "currentThreadCount";// tomcat的线程数对应的属性值 
 45             MBeanAttributeInfo[] mbAttributes = mbInfo.getAttributes(); 
 46             System.out.println("currentThreadCount:" 
 47                     + mbsc.getAttribute(threadObjName, attrName)); 
 48  
 49             // heap 
 50             for (int j = 0; j < mbsc.getDomains().length; j++) { 
 51                 System.out.println("###########" + mbsc.getDomains()[j]); 
 52             } 
 53             Set MBeanset = mbsc.queryMBeans(null, null); 
 54             System.out.println("MBeanset.size() : " + MBeanset.size()); 
 55             Iterator MBeansetIterator = MBeanset.iterator(); 
 56             while (MBeansetIterator.hasNext()) { 
 57                 ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator 
 58                         .next(); 
 59                 ObjectName objectName = objectInstance.getObjectName(); 
 60                 String canonicalName = objectName.getCanonicalName(); 
 61                 System.out.println("canonicalName : " + canonicalName); 
 62                 if (canonicalName 
 63                         .equals("Catalina:host=localhost,type=Cluster")) { 
 64                     // Get details of cluster MBeans 
 65                     System.out.println("Cluster MBeans Details:"); 
 66                     System.out 
 67                             .println("========================================="); 
 68                     // getMBeansDetails(canonicalName); 
 69                     String canonicalKeyPropList = objectName 
 70                             .getCanonicalKeyPropertyListString(); 
 71                 } 
 72             } 
 73             // ------------------------- system ---------------------- 
 74             ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime"); 
 75             System.out.println("厂商:" 
 76                     + (String) mbsc.getAttribute(runtimeObjName, "VmVendor")); 
 77             System.out.println("程序:" 
 78                     + (String) mbsc.getAttribute(runtimeObjName, "VmName")); 
 79             System.out.println("版本:" 
 80                     + (String) mbsc.getAttribute(runtimeObjName, "VmVersion")); 
 81             Date starttime = new Date((Long) mbsc.getAttribute(runtimeObjName, 
 82                     "StartTime")); 
 83             SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
 84             System.out.println("启动时间:" + df.format(starttime)); 
 85  
 86             Long timespan = (Long) mbsc.getAttribute(runtimeObjName, "Uptime"); 
 87             System.out.println("连续工作时间:" + JMXTest.formatTimeSpan(timespan)); 
 88             // ------------------------ JVM ------------------------- 
 89             // 堆使用率 
 90             ObjectName heapObjName = new ObjectName("java.lang:type=Memory"); 
 91             MemoryUsage heapMemoryUsage = MemoryUsage 
 92                     .from((CompositeDataSupport) mbsc.getAttribute(heapObjName, 
 93                             "HeapMemoryUsage")); 
 94             long maxMemory = heapMemoryUsage.getMax();// 堆最大 
 95             long commitMemory = heapMemoryUsage.getCommitted();// 堆当前分配 
 96             long usedMemory = heapMemoryUsage.getUsed(); 
 97             System.out.println("heap:" + (double) usedMemory * 100 
 98                     / commitMemory + "%");// 堆使用率 
 99  
100             MemoryUsage nonheapMemoryUsage = MemoryUsage 
101                     .from((CompositeDataSupport) mbsc.getAttribute(heapObjName, 
102                             "NonHeapMemoryUsage")); 
103             long noncommitMemory = nonheapMemoryUsage.getCommitted(); 
104             long nonusedMemory = heapMemoryUsage.getUsed(); 
105             System.out.println("nonheap:" + (double) nonusedMemory * 100 
106                     / noncommitMemory + "%"); 
107  
108             ObjectName permObjName = new ObjectName( 
109                     "java.lang:type=MemoryPool,name=Perm Gen"); 
110             MemoryUsage permGenUsage = MemoryUsage 
111                     .from((CompositeDataSupport) mbsc.getAttribute(permObjName, 
112                             "Usage")); 
113             long committed = permGenUsage.getCommitted();// 持久堆大小 
114             long used = heapMemoryUsage.getUsed();// 
115             System.out.println("perm gen:" + (double) used * 100 / committed 
116                     + "%");// 持久堆使用率 
117  
118             // -------------------- Session --------------- 
119             ObjectName managerObjName = new ObjectName( 
120                     "Catalina:type=Manager,*"); 
121             Set<ObjectName> s = mbsc.queryNames(managerObjName, null); 
122             for (ObjectName obj : s) { 
123                 System.out.println("应用名:" + obj.getKeyProperty("path")); 
124                 ObjectName objname = new ObjectName(obj.getCanonicalName()); 
125                 System.out.println("最大会话数:" 
126                         + mbsc.getAttribute(objname, "maxActiveSessions")); 
127                 System.out.println("会话数:" 
128                         + mbsc.getAttribute(objname, "activeSessions")); 
129                 System.out.println("活动会话数:" 
130                         + mbsc.getAttribute(objname, "sessionCounter")); 
131             } 
132  
133             // ----------------- Thread Pool ---------------- 
134             ObjectName threadpoolObjName = new ObjectName( 
135                     "Catalina:type=ThreadPool,*"); 
136             Set<ObjectName> s2 = mbsc.queryNames(threadpoolObjName, null); 
137             for (ObjectName obj : s2) { 
138                 System.out.println("端口名:" + obj.getKeyProperty("name")); 
139                 ObjectName objname = new ObjectName(obj.getCanonicalName()); 
140                 System.out.println("最大线程数:" 
141                         + mbsc.getAttribute(objname, "maxThreads")); 
142                 System.out.println("当前线程数:" 
143                         + mbsc.getAttribute(objname, "currentThreadCount")); 
144                 System.out.println("繁忙线程数:" 
145                         + mbsc.getAttribute(objname, "currentThreadsBusy")); 
146             } 
147  
148         } catch (Exception e) { 
149             e.printStackTrace(); 
150         } 
151     } 
152  
153     public static String formatTimeSpan(long span) { 
154         long minseconds = span % 1000; 
155  
156         span = span / 1000; 
157         long seconds = span % 60; 
158  
159         span = span / 60; 
160         long mins = span % 60; 
161  
162         span = span / 60; 
163         long hours = span % 24; 
164  
165         span = span / 24; 
166         long days = span; 
167         return (new Formatter()).format("%1$d天 %2$02d:%3$02d:%4$02d.%5$03d", 
168                 days, hours, mins, seconds, minseconds).toString(); 
169     } 
170 } 

 实例2:

  1 public ConcurrentHashMap<String, Object> parseJMS(String tempid, ConcurrentHashMap<String, Object> paraMap) {
  2         MBeanServerConnection mbsc = null;
  3         try {
  4             mbsc = connector.getMBeanServerConnection();
  5             // ------------------------- system ----------------------
  6             ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime");
  7             TabularDataSupport system = (TabularDataSupport) mbsc.getAttribute(runtimeObjName, "SystemProperties");
  8             //JVM版本
  9             paraMap.put(tempid + "_JVMVERSION", mbsc.getAttribute(runtimeObjName, "VmVersion"));
 10             //JVM厂商
 11             paraMap.put(tempid + "_JVMMANUFACTURER", mbsc.getAttribute(runtimeObjName, "VmVendor"));
 12             //系统结构
 13             paraMap.put(tempid + "_SYSTEMSTRUCTURE", system.get(new Object[] {"os.arch"}).get("value"));
 14             //操作系统
 15             paraMap.put(tempid + "_OPERATIONSYSTEM", system.get(new Object[] {"os.name"}).get("value"));
 16             //操作系统版本
 17             paraMap.put(tempid + "_OPERATIONSYSTEMVERSION", system.get(new Object[] {"os.version"}).get("value"));
 18             //Tomcat版本
 19             String t_version = (String) system.get(new Object[] {"org.apache.catalina.startup.TldConfig.jarsToSkip"}).get("value");
 20             paraMap.put(tempid + "_TOMCATVERSION", t_version == null ? "" : t_version.substring(0, t_version.indexOf("-")));
 21             //链接Tomcat服务器的响应时间 -------------
 22              
 23              
 24             ObjectName heapObjName = new ObjectName("java.lang:type=Memory");
 25             MemoryUsage heapMemoryUsage =  MemoryUsage.from((CompositeDataSupport)mbsc.getAttribute(heapObjName, "HeapMemoryUsage"));
 26             //JVM已用内存
 27             paraMap.put(tempid + "_JVMUSERDMEMORY", heapMemoryUsage.getUsed());
 28             //JVM可用内存
 29             paraMap.put(tempid + "_JVMAVAILABLEMEMORY", heapMemoryUsage.getCommitted() - heapMemoryUsage.getUsed());
 30             //JVM内存总数
 31             paraMap.put(tempid + "_JVMTOTALMEMORY", heapMemoryUsage.getCommitted());
 32               
 33           //----------------- GlobalRequestProcessor ----------------
 34            ObjectName requestProcessor = new ObjectName("Catalina:type=GlobalRequestProcessor,*");
 35            Set<ObjectName> s2 = mbsc.queryNames(requestProcessor, null);
 36            long bytesSents = 0;
 37            long bytesReceiveds = 0;
 38            Integer errorCounts = 0;
 39            Integer requestCounts = 0;
 40            long processingTimes = 0;
 41            long maxTimes = 0;
 42            for (ObjectName obj : s2) {
 43                ObjectName objname = new ObjectName(obj.getCanonicalName());
 44                long bytesSent = (long) mbsc.getAttribute( objname, "bytesSent");
 45                long bytesReceived = (long) mbsc.getAttribute( objname, "bytesReceived");
 46                Integer errorCount = (Integer) mbsc.getAttribute( objname, "errorCount");
 47                Integer requestCount = (Integer) mbsc.getAttribute( objname, "requestCount");
 48                long processingTime = (long) mbsc.getAttribute( objname, "processingTime");
 49                long maxTime = (long) mbsc.getAttribute( objname, "maxTime");
 50                bytesSents += bytesSent;
 51                bytesReceiveds += bytesReceived;
 52                errorCounts += errorCount;
 53                requestCounts += requestCount;
 54                processingTimes += processingTime;
 55                maxTimes += maxTime;
 56            }
 57            //发送字节
 58            paraMap.put(tempid + "_SENDBYTE", bytesSents);
 59            //接收字节
 60            paraMap.put(tempid + "_RECIEVEDBYTE", bytesReceiveds);
 61            //错误个数
 62            paraMap.put(tempid + "_ERRORNUMBER", errorCounts);
 63            //请求个数
 64            paraMap.put(tempid + "_REQUESTNUMBER", requestCounts);
 65            //处理时间
 66            paraMap.put(tempid + "_TREATMENTTIME", processingTimes);
 67            //最大处理时间
 68            paraMap.put(tempid + "_MAXTREATMENTTIME", maxTimes);
 69            
 70            //----------------- Thread Pool ----------------
 71            ObjectName threadpoolObjName = new ObjectName("Catalina:type=ThreadPool,*");
 72            Set<ObjectName> tp = mbsc.queryNames(threadpoolObjName, null);
 73            int currentThreadsBusys = 0;
 74            int maxThreadss = 0;
 75            for (ObjectName obj : tp) {
 76                ObjectName objname = new ObjectName(obj.getCanonicalName());
 77                int currentThreadsBusy = (int) mbsc.getAttribute( objname, "currentThreadsBusy");
 78                int maxThreads = (int) mbsc.getAttribute( objname, "maxThreads");
 79                currentThreadsBusys += currentThreadsBusy;
 80                maxThreadss += maxThreads;
 81            }
 82            //当前忙碌线程数
 83            paraMap.put(tempid + "_CURRENTBUSYTHREADSNUMBER", currentThreadsBusys);
 84            //最大线程数
 85            paraMap.put(tempid + "_MAXTHREADSNUMBER", maxThreadss);
 86             
 87            //----------------- RequestProcessor ----------------
 88            ObjectName requestProcessor1 = new ObjectName("Catalina:type=RequestProcessor,*");
 89            Set<ObjectName> rp = mbsc.queryNames(requestProcessor1, null);
 90            long requestProcessingTimes = 0;
 91            int portCount = 0;
 92            for (ObjectName obj : rp) {
 93                portCount++;
 94                ObjectName objname = new ObjectName(obj.getCanonicalName());
 95                long requestProcessingTime = (long) mbsc.getAttribute(objname, "requestProcessingTime");
 96                requestProcessingTimes += requestProcessingTime;
 97            }
 98            //端口平均响应时间
 99            paraMap.put(tempid + "_AVERAGERESPONSETIME", portCount == 0 ? requestProcessingTimes : Math.round(requestProcessingTimes/portCount));
100             
101             
102             
103         } catch (IOException e) {
104             e.printStackTrace();
105         } catch (MalformedObjectNameException e) {
106             e.printStackTrace();
107         } catch (AttributeNotFoundException e) {
108             e.printStackTrace();
109         } catch (InstanceNotFoundException e) {
110             e.printStackTrace();
111         } catch (MBeanException e) {
112             e.printStackTrace();
113         } catch (ReflectionException e) {
114             e.printStackTrace();
115         } catch (SecurityException e) {
116             e.printStackTrace();
117         } catch (IllegalArgumentException e) {
118             e.printStackTrace();
119         } 
120         return paraMap;
121     }
122   
123     public static void main(String[] args) {
124         DoJob job = new DoJob();
125         String tempid = "MW_WS_TOMCAT_AGENT";
126         job.connector = TomcatUtil.getJMXOfTomcat("service:jmx:rmi:///jndi/rmi://191.168.2.31:8999/jmxrmi", "", "");
127         ConcurrentHashMap<String, Object> paraMap = new ConcurrentHashMap<String, Object>();
128         paraMap = job.parseJMS(tempid, paraMap);
129         Iterator<String> it = paraMap.keySet().iterator();
130         while(it.hasNext()) {
131             String key = it.next();
132             System.out.println(key + " : " + paraMap.get(key));
133         }
134     }

 



posted on 2015-10-21 17:21  IMEIXI4EVER  阅读(2057)  评论(0编辑  收藏  举报