1. 程式人生 > >Tomcat學習--tomcat執行狀態監控

Tomcat學習--tomcat執行狀態監控

    上一篇部落格Tomcat學習--war服務相關狀態資訊監控中我們已經瞭解了一下對war包的啟動、停止、執行狀態、過載和解除安裝操作的實現機制,接下來我們用這篇部落格瞭解一下tomcat執行過程中伺服器,作業系統,jvm和war的一些狀態資訊。

    目前tomcat將執行的過程中的一些狀態資訊通過JMX的MBeanServer機制儲存起來,所以目前的實現就是通過MBeanServer來獲取資料就好,可以參考tomcat的StatusManagerServlet的實現邏輯。

    本篇部落格只是簡單的獲取了一些資料進行展示

1、web.xml中配置如下

<!-- 檢視tomcat中自身及每個war服務的執行情況 -->
  <servlet>
    <servlet-name>tomcat-monitor-info</servlet-name>
    <servlet-class>com.tianjunwei.tomcat.servlet.MonitorInfoServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>tomcat-monitor-info</servlet-name>
    <url-pattern>/tomcat_monitor_info</url-pattern>
  </servlet-mapping>

2、實現原始碼如下:

public class MonitorInfoServlet  extends HttpServlet implements NotificationListener {

	private static final long serialVersionUID = 1L;

	protected static MBeanServer mBeanServer = null;
	
	protected final Vector<ObjectName> protocolHandlers = new Vector<>();
	
	protected final Vector<ObjectName> threadPools = new Vector<>();
	
    protected final Vector<ObjectName> globalRequestProcessors = new Vector<>();
    
    protected final Vector<ObjectName> requestProcessors = new Vector<>();
	
	@Override
	public void init() throws ServletException {

		// Retrieve the MBean server
		mBeanServer = Registry.getRegistry(null, null).getMBeanServer();

		try {

			// Query protocol handlers
			String onStr = "*:type=ProtocolHandler,*";
			ObjectName objectName = new ObjectName(onStr);
			Set<ObjectInstance> set = mBeanServer.queryMBeans(objectName, null);
			Iterator<ObjectInstance> iterator = set.iterator();
			while (iterator.hasNext()) {
				ObjectInstance oi = iterator.next();
				protocolHandlers.addElement(oi.getObjectName());
			}

			// Query Thread Pools
			onStr = "*:type=ThreadPool,*";
			objectName = new ObjectName(onStr);
			set = mBeanServer.queryMBeans(objectName, null);
			iterator = set.iterator();
			while (iterator.hasNext()) {
				ObjectInstance oi = iterator.next();
				threadPools.addElement(oi.getObjectName());
			}

			// Query Global Request Processors
			onStr = "*:type=GlobalRequestProcessor,*";
			objectName = new ObjectName(onStr);
			set = mBeanServer.queryMBeans(objectName, null);
			iterator = set.iterator();
			while (iterator.hasNext()) {
				ObjectInstance oi = iterator.next();
				globalRequestProcessors.addElement(oi.getObjectName());
			}

			// Query Request Processors
			onStr = "*:type=RequestProcessor,*";
			objectName = new ObjectName(onStr);
			set = mBeanServer.queryMBeans(objectName, null);
			iterator = set.iterator();
			while (iterator.hasNext()) {
				ObjectInstance oi = iterator.next();
				requestProcessors.addElement(oi.getObjectName());
			}

			// Register with MBean server
			onStr = "JMImplementation:type=MBeanServerDelegate";
			objectName = new ObjectName(onStr);
			mBeanServer.addNotificationListener(objectName, this, null, null);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
		    throws IOException{
		PrintWriter writer = response.getWriter();
		Map<String, Object> dataMap = new HashMap<String,Object>();
		dataMap.put("server", getServerData());
		dataMap.put("os", getOsData());
		dataMap.put("jvm", getJVMData());
		dataMap.put("war", getWarData());
		writer.write(JSON.toJSONString(dataMap));
		writer.flush();
	}
	
	/**
	 * 獲取作業系統及jvm相關的資訊
	 */
	public static Map<String, Object> getServerData(){
		
		Map<String, Object> serverMap =new HashMap<String, Object>();
		serverMap.put("tomcat_version", ServerInfo.getServerInfo());
		serverMap.put("jvm_version", System.getProperty("java.runtime.version"));
		serverMap.put("jvm_vendor", System.getProperty("java.vm.vendor"));
		serverMap.put("os_name", System.getProperty("os.name"));
		serverMap.put("os_version", System.getProperty("os.version"));
		serverMap.put("os_arch", System.getProperty("os.arch"));
		
        try {
            InetAddress address = InetAddress.getLocalHost();
            serverMap.put("hostName", address.getHostName());
            serverMap.put("hostAddress", address.getHostAddress());
         } catch (UnknownHostException e) {
        	 serverMap.put("hostName", "-");
             serverMap.put("hostAddress", "-");
        }
		return serverMap;
	}
	
	/**
	 * 
	 * 獲取作業系統相關資訊
	 */
	public static Map<String, Object> getOsData(){
		Map<String, Object> osMap = new HashMap<String, Object>();
		long[] result = new long[16];
	    boolean ok = false;
	    try {
	    	String methodName = "info";
	    	Class<?> paramTypes[] = new Class[1];
	    	paramTypes[0] = result.getClass();
	    	Object paramValues[] = new Object[1];
	    	paramValues[0] = result;
	    	Method method = Class.forName("org.apache.tomcat.jni.OS")
	                .getMethod(methodName, paramTypes);
	    	method.invoke(null, paramValues);
	    	ok = true;
	    } catch (Throwable t) {
	    	t = ExceptionUtils.unwrapInvocationTargetException(t);
	    	ExceptionUtils.handleThrowable(t);
	    }

	    if (ok) {
	    	osMap.put(" Physical memory",formatSize(Long.valueOf(result[0]), true));
	    	osMap.put(" Available memory: ",formatSize(Long.valueOf(result[1]), true));
	    	osMap.put(" Total page file: ",formatSize(Long.valueOf(result[2]), true));
	    	osMap.put(" Free page file: ",formatSize(Long.valueOf(result[3]), true));
	    	osMap.put(" Memory load: ",Long.valueOf(result[6]));
	    	osMap.put(" Process kernel time: ",formatTime(Long.valueOf(result[11] / 1000), true));
	    	osMap.put(" Process user time: ",formatTime(Long.valueOf(result[12] / 1000), true));
	    }
		return osMap;
	}
	
	public static Map<String, Object> getJVMData(){
		Map<String, Object> jvmMap = new HashMap<String,Object>();
		SortedMap<String, MemoryPoolMXBean> memoryPoolMBeans = new TreeMap<>();
        for (MemoryPoolMXBean mbean: ManagementFactory.getMemoryPoolMXBeans()) {
            String sortKey = mbean.getType() + ":" + mbean.getName();
            memoryPoolMBeans.put(sortKey, mbean);
        }
        jvmMap.put("free_memory",Runtime.getRuntime().freeMemory());
        jvmMap.put("total_memory",Runtime.getRuntime().totalMemory());
        jvmMap.put("max_memory" , Runtime.getRuntime().maxMemory());

        List<Map<String, Object>> memory_list = new ArrayList<Map<String, Object>>();
        jvmMap.put("memory_pool", memory_list);
        for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) {
            MemoryUsage usage = memoryPoolMBean.getUsage();
            Map<String, Object> useMap = new HashMap<String, Object>();
            useMap.put("name",memoryPoolMBean.getName());
            useMap.put("type",memoryPoolMBean.getType());
            useMap.put("usageInit",usage.getInit());
            useMap.put("usageCommitted",usage.getCommitted());
            useMap.put("usageMax",usage.getMax());
            useMap.put("usageUsed",usage.getUsed());
            memory_list.add(useMap);
        }
        return jvmMap;
	}
	
	
	
	public static Map<String,Object> getWarData(){
		Map<String,Object> dataMap=new HashMap<String, Object>();
		try {
			//堆使用
			ObjectName heapObjName = new ObjectName("java.lang:type=Memory");
			MemoryUsage heapMemoryUsage = MemoryUsage
					.from((CompositeDataSupport) mBeanServer.getAttribute(heapObjName, "HeapMemoryUsage"));
			dataMap.put("memoryUse", heapMemoryUsage.getUsed());
			dataMap.put("memoryMax", heapMemoryUsage.getMax());
			ObjectName runtimeObjName = new ObjectName("java.lang:type=Runtime");
			RuntimeMXBean runtimeMXBean=ManagementFactory.getPlatformMXBean
					(mBeanServer, RuntimeMXBean.class); 
			dataMap.put("uptime",runtimeMXBean.getUptime());
			//永久代使用
			ObjectName metaObjName = new ObjectName("java.lang:type=MemoryPool,name=Metaspace");
			MemoryUsage metaMemoryUsage = MemoryUsage
					.from((CompositeDataSupport) mBeanServer.getAttribute(metaObjName, "Usage"));
			dataMap.put("metaspaceUse", (int)(metaMemoryUsage.getUsed()/(1024*1024)));
			dataMap.put("metaspaceMax", (int)(metaMemoryUsage.getMax()/(1024*1024)));
			//執行緒數連線數
			ObjectName threadObjName = new ObjectName("Catalina:type=ThreadPool,name=*");
			ObjectName threadMXBean=mBeanServer.queryNames(threadObjName, null).iterator().next();
			dataMap.put("connectionCount", mBeanServer.getAttribute(threadMXBean, "connectionCount"));
			dataMap.put("maxConnections", mBeanServer.getAttribute(threadMXBean, "maxConnections"));
			dataMap.put("currentThreadCount", mBeanServer.getAttribute(threadMXBean, "currentThreadCount"));
			dataMap.put("maxThreads", mBeanServer.getAttribute(threadMXBean, "maxThreads"));

			//請求、錯誤請求、傳送接收資料量
			ObjectName grpObjName = new ObjectName("Catalina:type=GlobalRequestProcessor,*");
			ObjectName requObjName=mBeanServer.queryNames(grpObjName, null).iterator().next();
			dataMap.put("requestCount", mBeanServer.getAttribute(requObjName, "requestCount"));
			dataMap.put("errorCount", mBeanServer.getAttribute(requObjName, "errorCount"));
			//context
			Host host = MyHostConfig.myHost;
			List<Map<String,Object>> contexts=new ArrayList<Map<String,Object>>();
			for(Container container:host.findChildren()){
				Context context=(Context)container;
				String name=context.getName().trim();
				if("".equals(name)){
					continue;
				}
				contexts.add(parseContext(context,mBeanServer));
			}
			dataMap.put("contexts", contexts);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return dataMap;
	}
	
	private static Map<String,Object> parseContext(Context context,MBeanServer mbsc) throws Exception{
		Map<String,Object> contextMap=new HashMap<String,Object>();
		ObjectName objectName=context.getObjectName();		
		contextMap.put("name", context.getName().trim());
		contextMap.put("state", context.getStateName());
/*		contextMap.put("sessionTimeout", context.getSessionTimeout());*/
		contextMap.put("requestCount", mbsc.getAttribute(objectName, "requestCount"));
		contextMap.put("errorCount", mbsc.getAttribute(objectName, "errorCount"));
		Manager manager=context.getManager();
		Session[] sessions=manager.findSessions();
		contextMap.put("sessionCount", sessions.length);
		List<Map<String,Object>> sessionsInfo=new ArrayList<>();
		for(int i=0;i<sessions.length;i++){
			Map<String,Object> session=new HashMap<>();
			session.put("sessionId", sessions[i].getId());
//			session.put("viewIp", sessions[i].getSession().ge);
			session.put("idleTIme", sessions[i].getIdleTime());
			session.put("inactiveIntervalTime", sessions[i].getMaxInactiveInterval());
			session.put("lastAcessTime", sessions[i].getLastAccessedTime());
			sessionsInfo.add(session);
		}
		contextMap.put("sessions", sessionsInfo);
		return contextMap;
	}
	
	
	 public static Map<String,Object> getData(){
	    	MBeanServer mBeanServer = Registry.getRegistry(null,null).getMBeanServer();
	    	String onStr = "*:type=ThreadPool,*";
	    	Map<String,Object> map = new HashMap<String,Object>();
	    	try{
	    		ObjectName objectName = new ObjectName(onStr);
	    		Set set = mBeanServer.queryMBeans(objectName, null);
	    		Vector<ObjectName> threadPool = new Vector<ObjectName>();  		
	        	Iterator iterator = set.iterator();
	        	while(iterator.hasNext()){
	        		ObjectInstance oi = (ObjectInstance) iterator.next();
	        	    threadPool.addElement(oi.getObjectName());
	        	}
	        	Vector<ObjectName> globalRequestProcessors = new Vector<ObjectName>();
	        	onStr = "*:type=GlobalRequestProcessor,*";
	        	objectName = new ObjectName(onStr);
	        	set.clear();
	        	set = mBeanServer.queryMBeans(objectName, null);
	        	iterator = set.iterator();
	        	while(iterator.hasNext()){
	        		ObjectInstance oi = (ObjectInstance) iterator.next();
	        		globalRequestProcessors.addElement(oi.getObjectName());
	        	}
	        	Enumeration<ObjectName> enumeration = threadPool.elements();
	        	while(enumeration.hasMoreElements()){
	        		ObjectName objectName1 = enumeration.nextElement();
	        		map.put("maxThread", mBeanServer.getAttribute(objectName1, "maxThreads"));
	        		map.put("currentThreadCount", mBeanServer.getAttribute(objectName1, "currentThreadCount"));
	        		map.put("connectionCount", mBeanServer.getAttribute(objectName1, "connectionCount"));
	        		map.put("maxConnections", mBeanServer.getAttribute(objectName1, "maxConnections"));
	        	}
	        	
	        	Enumeration<ObjectName> reqEnume  = globalRequestProcessors.elements();
	        	while(reqEnume.hasMoreElements()){
	        		ObjectName reqObjectName = reqEnume.nextElement();
	        		map.put("processingTime", mBeanServer.getAttribute(reqObjectName, "processingTime"));
	        		map.put("requestCount", mBeanServer.getAttribute(reqObjectName, "requestCount"));
	        		map.put("errorCount", mBeanServer.getAttribute(reqObjectName, "errorCount"));
	        	}
	        	
	        	map.put("maxMemory", formatSize(Long.valueOf(Runtime.getRuntime().maxMemory()), true));
	        	SortedMap<String, MemoryPoolMXBean> memoryPoolMBeans = new TreeMap<String, MemoryPoolMXBean>();
	    		for (MemoryPoolMXBean mbean : ManagementFactory.getMemoryPoolMXBeans()) {
	    			String sortKey = mbean.getType() + ":" + mbean.getName();
	    			memoryPoolMBeans.put(sortKey, mbean);
	    		}
	    		Long usedMemory = 0l;
	    		for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) {
	    			MemoryUsage usage = memoryPoolMBean.getUsage();
	    			usedMemory = usedMemory + Long.valueOf(usage.getUsed());
	    		}
	    		map.put("usedMemory", formatSize(usedMemory, true));
	    		/*long connectionCount = (Long) mBeanServer.getAttribute(objectNameData, "connectionCount");
				int maxConnections = (int) mBeanServer.getAttribute(objectNameData, "maxConnections");*/
	    	}catch(Exception e){
	    		e.printStackTrace();
	    	}
			return map;
	    
	    }
	    
	    public static long formatSize(Object obj, boolean mb) {

			long bytes = -1L;

			if (obj instanceof Long) {
				bytes = ((Long) obj).longValue();
			} else if (obj instanceof Integer) {
				bytes = ((Integer) obj).intValue();
			}

			if (mb) {
				StringBuilder buff = new StringBuilder();
				if (bytes < 0) {
					buff.append('-');
					bytes = -bytes;
				}
				long mbytes = bytes / (1024 * 1024);
				long rest = ((bytes - (mbytes * (1024 * 1024))) * 100) / (1024 * 1024);
				buff.append(mbytes).append('.');
				if (rest < 10) {
					buff.append('0');
				}
				buff.append(rest);
				double d = Double.parseDouble(buff.toString());
				Long l = (long) d;
				return l;
			} else {
				return (bytes / 1024);
			}

		}
	    
	    public static String formatTime(Object obj) {

	        long time = -1L;

	        if (obj instanceof Long) {
	            time = ((Long) obj).longValue();
	        } else if (obj instanceof Integer) {
	            time = ((Integer) obj).intValue();
	        }

	        if (time > 1000 *1000) {
	            return ((((float) time ) / 1000) + " s");
	        } else if(time > 1000) {
	            return (time + " ms");
	        }else {
	        	 return ((((float) time ) / 1000) + " ms");
			}
	    }
	    public static String formatTime(Object obj, boolean seconds) {

	        long time = -1L;

	        if (obj instanceof Long) {
	            time = ((Long) obj).longValue();
	        } else if (obj instanceof Integer) {
	            time = ((Integer) obj).intValue();
	        }

	        if (seconds) {
	            return ((((float) time ) / 1000) + " s");
	        } else {
	            return (time + " ms");
	        }
	    }

	    @Override
	    public void handleNotification(Notification notification,
	                                   java.lang.Object handback) {

	        if (notification instanceof MBeanServerNotification) {
	            ObjectName objectName =
	                ((MBeanServerNotification) notification).getMBeanName();
	            if (notification.getType().equals
	                (MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
	                String type = objectName.getKeyProperty("type");
	                if (type != null) {
	                    if (type.equals("ProtocolHandler")) {
	                        protocolHandlers.addElement(objectName);
	                    } else if (type.equals("ThreadPool")) {
	                        threadPools.addElement(objectName);
	                    } else if (type.equals("GlobalRequestProcessor")) {
	                        globalRequestProcessors.addElement(objectName);
	                    } else if (type.equals("RequestProcessor")) {
	                        requestProcessors.addElement(objectName);
	                    }
	                }
	            } else if (notification.getType().equals
	                       (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
	                String type = objectName.getKeyProperty("type");
	                if (type != null) {
	                    if (type.equals("ProtocolHandler")) {
	                        protocolHandlers.removeElement(objectName);
	                    } else if (type.equals("ThreadPool")) {
	                        threadPools.removeElement(objectName);
	                    } else if (type.equals("GlobalRequestProcessor")) {
	                        globalRequestProcessors.removeElement(objectName);
	                    } else if (type.equals("RequestProcessor")) {
	                        requestProcessors.removeElement(objectName);
	                    }
	                }
	                String j2eeType = objectName.getKeyProperty("j2eeType");
	                if (j2eeType != null) {

	                }
	            }
	        }

	    }
	    
	
}

3、獲取的結果資料如下:

{
	"jvm": {
		"total_memory": 48758784,
		"memory_pool": [{
			"usageMax": 11010048,
			"name": "PS Eden Space",
			"usageUsed": 6111136,
			"type": "HEAP",
			"usageCommitted": 10485760,
			"usageInit": 13107200
		}, {
			"usageMax": 35127296,
			"name": "PS Old Gen",
			"usageUsed": 19668376,
			"type": "HEAP",
			"usageCommitted": 35127296,
			"usageInit": 35127296
		}, {
			"usageMax": 3145728,
			"name": "PS Survivor Space",
			"usageUsed": 1950184,
			"type": "HEAP",
			"usageCommitted": 3145728,
			"usageInit": 2097152
		}, {
			"usageMax": 104857600,
			"name": "Code Cache",
			"usageUsed": 11987072,
			"type": "NON_HEAP",
			"usageCommitted": 12255232,
			"usageInit": 2555904
		}, {
			"usageMax": 1073741824,
			"name": "Compressed Class Space",
			"usageUsed": 3185400,
			"type": "NON_HEAP",
			"usageCommitted": 3538944,
			"usageInit": 0
		}, {
			"usageMax": -1,
			"name": "Metaspace",
			"usageUsed": 31663032,
			"type": "NON_HEAP",
			"usageCommitted": 32636928,
			"usageInit": 0
		}],
		"free_memory": 21029088,
		"max_memory": 48758784
	},
	"server": {
		"hostName": "nb-hz20036325",
		"tomcat_version": "Apache Tomcat/8.5.24",
		"jvm_vendor": "Oracle Corporation",
		"os_version": "6.1",
		"os_arch": "amd64",
		"os_name": "Windows 7",
		"hostAddress": "10.13.80.12",
		"jvm_version": "1.8.0_151-b12"
	},
	"os": {
		" Free page file: ": 17006,
		" Available memory: ": 4869,
		" Physical memory": 12241,
		" Process user time: ": "12.324 s",
		" Total page file: ": 24481,
		" Process kernel time: ": "7.254 s",
		" Memory load: ": 60
	},
	"war": {
		"requestCount": 112,
		"connectionCount": 2,
		"currentThreadCount": 10,
		"memoryMax": 48758784,
		"metaspaceUse": 30,
		"contexts": [{
			"requestCount": 0,
			"sessions": [],
			"sessionCount": 0,
			"name": "/examples",
			"state": "STARTED",
			"errorCount": 0
		}, {
			"requestCount": 0,
			"sessions": [],
			"sessionCount": 0,
			"name": "/host-manager",
			"state": "STARTED",
			"errorCount": 0
		}, {
			"requestCount": 48,
			"sessions": [{
				"inactiveIntervalTime": 1800,
				"lastAcessTime": 1525247083747,
				"sessionId": "11C58869BBF32D217EFF3F8B725982E6",
				"idleTIme": 612935
			}],
			"sessionCount": 1,
			"name": "/manager",
			"state": "STARTED",
			"errorCount": 1
		}, {
			"requestCount": 9,
			"sessions": [],
			"sessionCount": 0,
			"name": "/docs",
			"state": "STARTED",
			"errorCount": 0
		}, {
			"requestCount": 2,
			"sessions": [],
			"sessionCount": 0,
			"name": "/war_mointor",
			"state": "STARTED",
			"errorCount": 0
		}],
		"maxThreads": 200,
		"errorCount": 4,
		"memoryUse": 27729696,
		"uptime": 11892453,
		"metaspaceMax": 0,
		"maxConnections": 10000
	}
}
程式碼地址Github