내용 목차
JEUS MBean 정보를 모니터링하는 4가지 중요한 예제를 설명한다.
설명하는 모든 예제에서 MBean 서버 정보를 조회할 때 RemoteMBeanServerFactory를 이용한다. MBean 서버를 얻어오는 다른 방법에 대한 자세한 내용은 “제3장 JMX 애플리케이션 개발”을 참고한다.
Servlet Thread Info 모니터링 예제는 웹 컨테이너의 리스너의 정보, 특히 Thread Pool과 각 Thread에 대한 정보를 모니터링한다.
이 예제를 통해 모니터링하는 정보는 다음과 같다.
현재 할당된 Worker Thread의 수(current thread count)
Thread Pool을 유지하는 최대 Thread의 개수(max thread count)
Wait-Queue에 적체된 클라이언트의 수(wait queue count)
다음은 Servlet Thread Info 모니터링 예제이다.
package monitoring; import java.util.*; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.ObjectInstance; import javax.management.MalformedObjectNameException; import javax.management.MBeanServerInvocationHandler; import jeus.management.j2ee.servlet.*; public class ServletThreadInfo { public void showInfo(MBeanServerConnection mBeanServer, String targetName) throws Exception { System.out.println("=== Servlet Thread Info ==="); // Get the object name of the servlet engine using JMX Standard API // Otherwise, the object name could be queried through MBeanServer. // Please see JEUS MBean API javadoc for more concrete name, key properties. ObjectName name = new ObjectName("JEUS:jeusType=WebEngine,J2EEServer=" + targetName + ",*"); Set names = mBeanServer.queryMBeans(name, null); if (names == null || names.size() == 0) { System.out.println("there is no servlet engine"); return; } // Choose one servlet engine from the returned object names Iterator it = names.iterator(); ObjectName fullName = null; while (it.hasNext()) { fullName = ((ObjectInstance)it.next()).getObjectName(); break; } assert fullName != null; WebEngineMoMBean engineMBean = (WebEngineMoMBean)MBeanServerInvocationHandler.newProxyInstance(mBeanServer, fullName, WebEngineMoMBean.class, false); // Get listeners from WebEngine String[] listeners = engineMBean.getWebListeners(); if(listeners == null || listeners.length == 0){ return; } String webEngineName = engineMBean.getObjectName().getKeyProperty("name"); for(int i = 0; i < listeners.length; i++) { ObjectName listener = new ObjectName(listeners[i]); WebListenerMoMBean listenerMBean= (WebListenerMoMBean) MBeanServerInvocationHandler.newProxyInstance (mBeanServer, listener, WebListenerMoMBean.class, false); String[] tpoolNames = listenerMBean.getThreadPools(); // Get stats from thread pools if (tpoolNames != null) { showThreadPoolStats(mBeanServer, webEngineName, tpoolNames); } } System.out.println(); } private void showThreadPoolStats(MBeanServerConnection mBeanServer, String contextGroupName, String[] tpoolNames) throws MalformedObjectNameException { for (int k = 0; k < tpoolNames.length; k++) { ObjectName tpool = new ObjectName(tpoolNames[k]); System.out.println("[MBean] " + tpool); ThreadPoolMoMBean tpoolMBean = (ThreadPoolMoMBean)MBeanServerInvocationHandler.newProxyInstance( mBeanServer,tpool, ThreadPoolMoMBean.class, false); ThreadPoolStatsImpl stats = (ThreadPoolStatsImpl) tpoolMBean.getstats(); System.out.println("Listener: " + contextGroupName + "/" + tpool.getKeyProperty("name")); System.out.println("- current thread count : " + stats.getAllThreadCount().getCount()); System.out.println("- max thread count : " + stats.getMaxThreadCount().getCount()); if (stats.getStatisticVersion() == ThreadPoolStatsImpl.NIO_VERSION) { // pipeline System.out.println("- total connection count : " + stats.getTotalConnectionCount().getCount()); System.out.println("- max queue count : " + stats.getMaxQueueCount().getCount()); System.out.println("- current queue count : " + stats.getCurrentQueueCount().getCount()); System.out.println("- remain queue count : " + stats.getRemainQueueCount().getCount()); System.out.println("- peak queue count : " + stats.getPeakQueueCount().getCount()); System.out.println("- total queue count : " + stats.getTotalQueueCount().getCount()); System.out.println("- difference queue 1m count : " + stats.getDifferenceQueue1MCount().getCount()); System.out.println("- difference queue 5m count : " + stats.getDifferenceQueue5MCount().getCount()); System.out.println("- difference queue 15m count : " + stats.getDifferenceQueue15MCount().getCount()); System.out.println("- overflow queue count : " + stats.getOverflowCount().getCount()); System.out.println("- average queue time : " + stats.getQueueWaitTimeAverage().getCount() + "(ms)"); } else { System.out.println("- wait queue count : " + stats.getWaitQueueCount().getCount()); } System.out.println(); } } }
Thread Pool Info 모니터링 예제는 JEUS 에서 사용하는 여러 Thread Pool의 상태를 모니터링한다.
이 예제를 통해 모니터링하는 정보는 다음과 같다.
Thread Pool 크기(size)에 대한 정보
Thread Pool 통계(stats) 정보
Thread 들의 수행시간에 대한 통계(execution time stats) 정보
Waiting-Queue 크기에 대한 통계(size stats) 정보
다음은 Thread Info 모니터링 예제이다.
package monitoring; import java.util.Hashtable; import java.util.Iterator; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.j2ee.statistics.TimeStatistic; import javax.management.j2ee.statistics.RangeStatistic; import javax.naming.*; import jeus.jndi.JNSConstants; import jeus.management.JMXConstants; import jeus.management.RemoteMBeanServerFactory; import jeus.management.j2ee.thread.ThreadPoolMBean; import jeus.management.j2ee.thread.stats.ThreadPoolStats; public class ThreadPoolInfo { public void showInfo(MBeanServerConnection mBeanServer, String name) throws Exception { System.out.println("=== ThreadPool Info ==="); // Get the object names of the thread pools. // Please see JEUS MBean API javadoc for more concrete name, key // properties. ObjectName objectNames = new ObjectName("JEUS:jeusType=ThreadPool,*"); Set tpMBeans = mBeanServer.queryMBeans(objectNames, null); for (Iterator i = tpMBeans.iterator(); i.hasNext();) { ObjectName mbeanName = ((ObjectInstance) i.next()).getObjectName(); // thread pool name System.out.println("[Thread-pool : " + mbeanName.getKeyProperty("name") + "]"); System.out.println("[MBean] " + mbeanName); ThreadPoolMBean pool = (ThreadPoolMBean)MBeanServerInvocationHandler.newProxyInstance( mBeanServer, mbeanName, ThreadPoolMBean.class, false); // ThreadPool Size System.out.println("-size : " + pool.getPoolSize()); System.out.println("-core size : " + pool.getCorePoolSize()); System.out.println("-largest Size : " + pool.getLargestPoolSize()); System.out.println("-max size : " + pool.getMaximumPoolSize()); System.out.println("-queue size : " + pool.getWorkQueueSize()); // ThreadPool Stats ThreadPoolStats stats = (ThreadPoolStats) pool.getstats(); TimeStatistic executionTimeStats = stats.getThreadExecutionTime(); TimeStatistic waitingTimeStats = stats.getQueueWaitingTime(); System.out.println("# Thread Execution Time Stats"); System.out.println("--unit : " + executionTimeStats.getUnit()); System.out.println("--count : " + executionTimeStats.getCount()); System.out.println("--min time : " + executionTimeStats.getMinTime()); System.out.println("--max time : " + executionTimeStats.getMaxTime()); System.out.println("# Queue Waiting Time Stats"); System.out.println("--unit : " + waitingTimeStats.getUnit()); System.out.println("--count : " + waitingTimeStats.getCount()); System.out.println("--min time : " + waitingTimeStats.getMinTime()); System.out.println("--max time : " + waitingTimeStats.getMaxTime()); } } }
JVM Info 모니터링 예제는 JEUS의 노드 또는 컨테이너의 JVM에 대해 모니터링을 한다. 이 예제를 통해 모니터하는 정보는 다음과 같다.
JVM의 Total size 정보
JVM의 Heap size 정보
JVM의 Uptime 정보
다음은 JVM Info 모니터링 예제이다.
package monitoring; import java.util.Iterator; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.j2ee.statistics.BoundedRangeStatistic; import javax.management.j2ee.statistics.CountStatistic; import javax.management.j2ee.statistics.RangeStatistic; import jeus.management.j2ee.JVMMBean; import jeus.management.j2ee.statistics.JVMStatsImpl; public class JVMInfo { public void showInfo(MBeanServerConnection mBeanServer, String targetName) throws Exception { System.out.println("=== JVM Statistics ==="); ObjectName objectName = new ObjectName("JEUS:j2eeType=JVM,name=" + targetName + ",*"); Set jvmMBeans = mBeanServer.queryMBeans(objectName, null); for (Iterator i = jvmMBeans.iterator(); i.hasNext();) { ObjectName objName = ((ObjectInstance) i.next()).getObjectName(); System.out.println("[MBean] " + objName); // JVMMBean Stats JVMMBean jvm = (JVMMBean)MBeanServerInvocationHandler.newProxyInstance( mBeanServer, objName, JVMMBean.class, false); JVMStatsImpl jvmstatsimpl = (JVMStatsImpl) jvm.getstats(); RangeStatistic totalSize = jvmstatsimpl.getTotalSize(); BoundedRangeStatistic heapSize = jvmstatsimpl.getHeapSize(); CountStatistic upTime = jvmstatsimpl.getUpTime(); // JVM Total Size System.out.println("[Total Size]"); System.out.println("-unit : " + totalSize.getUnit()); System.out.println("-current : " + totalSize.getCurrent()); System.out.println("-min size : " + totalSize.getLowWaterMark()); System.out.println("-max size : " + totalSize.getHighWaterMark()); // JVM Heap Size System.out.println("[Heap Size]"); System.out.println("-unit : " + heapSize.getUnit()); System.out.println("-current : " + heapSize.getCurrent()); System.out.println("-min Size : " + heapSize.getLowWaterMark()); System.out.println("-max Size : " + heapSize.getHighWaterMark()); System.out.println("-lower bound : " + heapSize.getLowerBound()); System.out.println("-upper bound : " + heapSize.getUpperBound()); // JVM UpTime System.out.println("[Up Time]"); System.out.println("-unit : " + upTime.getUnit()); System.out.println("-count : " + upTime.getCount()); System.out.println("-start time : " + upTime.getStartTime()); } } }
본 절에서 설명하는 예제는 서버에 존재하는 DB Connection Pool을 모니터링한다. 여기에는 javax.management.remote.JMXConnector을 이용하여 MBean Connection을 얻는 예제도 함께 포함되어 있다.
이 예제의 내용은 다음과 같다.
특정 서버의 MBean 서버로 연결한다.
jeus.management.j2ee.JDBCResourceMBean을 조회해서 현재 생성된 Connection Pool들의 정보를 주기적으로 파일에 남긴다.
Connection Pool은 기동할 때 생성되지 않고 실제 서비스 호출 시점에 생성된다.
다음은 DB Connection Pool 모니터링 예제이다.
package monitoring; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Hashtable; import java.util.Iterator; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.j2ee.statistics.JDBCConnectionPoolStats; import javax.management.j2ee.statistics.JDBCStats; import javax.management.remote.JMXConnector; import javax.naming.Context; import javax.naming.InitialContext; import jeus.management.JMXConstants; import jeus.management.j2ee.JDBCResourceMBean; public class DBStatsClient { public static void main(String[] args) { String serverName = "changeplz"; //e.g. server1 Hashtable<String, Object> env = new Hashtable<String,Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JNSContextFactory"); env.put(Context.URL_PKG_PREFIXES, "jeus.jndi.jns.url"); env.put(Context.PROVIDER_URL, "localhost:9736"); MBeanServerConnection mbsc; try { InitialContext ctx = new InitialContext(env); JMXConnector connector = (JMXConnector)ctx.lookup( JMXConstants.JNDI_BINDING_PREFIX + serverName); connector.connect(); mbsc = connector.getMBeanServerConnection(); } catch (Exception e) { e.printStackTrace(); return; } System.out.println("mbean server connection successfully established"); Set mbeans; try { ObjectName dbstats = new ObjectName("JEUS:j2eeType=JDBCResource,*"); mbeans = mbsc.queryMBeans(dbstats, null); } catch (Exception e) { e.printStackTrace(); return; } System.out.println("Successfully get JDBCResource"); File file = new File(serverName+".log"); FileOutputStream stream = null; try { stream = new FileOutputStream(file); } catch (IOException e) { e.printStackTrace(); return; } while(true) { for (Iterator iter = mbeans.iterator();iter.hasNext();) { ObjectName jdbcResourceMBeanName = ((ObjectInstance) iter.next()).getObjectName(); JDBCResourceMBean jdbcResource = (JDBCResourceMBean) MBeanServerInvocationHandler.newProxyInstance( mbsc, jdbcResourceMBeanName, JDBCResourceMBean.class, false); JDBCStats jdbcStats = (JDBCStats) jdbcResource.getstats(); SimpleDateFormat format = new SimpleDateFormat("[MM-dd]HH:mm:ss"); StringBuilder builder = new StringBuilder(); builder.append("[STA] "); for (JDBCConnectionPoolStats cpStats : jdbcStats.getConnectionPools()) { String output =format.format(new Date(System.currentTimeMillis())) + " name:[" +cpStats.getJdbcDataSource() + "]" + " total:[" +cpStats.getPoolSize().getCurrent() +"]" + " use:[" + (cpStats.getPoolSize().getCurrent() - cpStats.getFreePoolSize().getCurrent()) +"] "; builder.append(output); } builder.append("\n"); try { stream.write(builder.toString().getBytes()); } catch (IOException e) { e.printStackTrace(); return; } } try { Thread.sleep(10000); } catch (InterruptedException e) { return; } } } }