1. 程式人生 > >Tomcat擴展——監控

Tomcat擴展——監控

jmx 能夠 tor lai elements del sse receive 也會


(轉過來,源地址:http://www.jmatrix.org/notes/1067.html)


近期心血來潮。想能否夠通過添加一個tomcat的擴展,來持續收集tomcatserver本身的性能信息。如線程池的各項數據,請求數等等,這樣能夠配合業務方面的監控,能夠更方便的分析調整tomcat配置,以提供更好的服務。

這樣也不須要每次通過連接jmx去觀察數據,並且idc環境要開啟jmx。還得涉及各種安全問題…….

Tomcat manager中StatusManagerServlet就是通過JMX提供了Tomcat服務的當前狀態信息。我也會“抄襲”這裏的代碼來收集server數據。

要想定時的收集Tomcat的數據,須要在tomcat啟動過程中,啟一個定時任務去不停的收集服務信息,之後依據自己的須要,看是通過寫日誌方式保存。還是上報,抑或其他方式。

要做到不侵入tomcat本身源代碼。能夠選擇通過Listener的方式,實現一個自己定義Listener,監聽服務啟動事件,啟動數據採集任務。定時收集數據,如:

public class ServerInfoMonitorLifecycleListener implementsLifecycleListener {

      private ServerInfoCollection collect = new ServerInfoCollection();

      @Override
      public void lifecycleEvent(LifecycleEvent event ) {
          Lifecycle lifecycle = event .getLifecycle();
           if (Lifecycle.AFTER_START_EVENT .equals(event .getType())
                   && lifecycle instanceof Server) {
               collect.startMonitor();
          }
           if (Lifecycle.BEFORE_STOP_EVENT .equals(event .getType())
                   && lifecycle instanceof Server) {
               collect.stopMonitor();
          }
     }
}

這裏監控的是Server的啟動事件,須要註意。假設你想監控其他container,如host。context等。則配置listener的時候須要放到相應的container。大多數情況下。我們還是習慣配置在Server這一級別,確實在Server這一級別是最方便的。

Tomcat本身的個別listener。想監聽host,context等的事件是通過監聽到Server事件的時候依次對server以下的host,context等加入listener。

有了定時收集tomcat數據的定時任務,以下就是數據的收集了。

首先得先獲取須要的Mbean。如:

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

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

               // Query Global Request Processors
               globalRequestProcessors .clear();
               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());
              }

          } catch (Exception e ) {
               log.error( "init failed." , e );
          }

通過Mbean獲取tomcat性能數據:

Enumeration enumeration = threadPools .elements();
               while (enumeration .hasMoreElements()) {
                   ObjectName objectName = enumeration .nextElement();
                   String name = objectName .getKeyProperty("name" );

                   ServerInfo serverInfo = new ServerInfo();
                    serverInfo .setMaxThreads((Integer) mBeanServer .getAttribute(
                              objectName , "maxThreads" ));
                    serverInfo .setCurrentThreadCount((Integer) mBeanServer
                             .getAttribute( objectName ,"currentThreadCount" ));
                    serverInfo .setCurrentThreadsBusy((Integer) mBeanServer
                             .getAttribute( objectName ,"currentThreadsBusy" ));
                    try {
                        Object value = mBeanServer .getAttribute(objectName ,
                                   "keepAliveCount" );
                         serverInfo .setKeepAliveCount((Integer) value );
                   } catch (Exception e ) {
                         // Ignore
                   }

                   ObjectName grpName = null ;
                   Enumeration reqEnumer =globalRequestProcessors
                             .elements();
                    while (reqEnumer .hasMoreElements()) {
                        ObjectName reqObjName = reqEnumer .nextElement();
                         if (name .equals(reqObjName .getKeyProperty( "name"))) {
                              grpName = reqObjName ;
                        }
                   }

                    if (grpName == null) {
                         return ;
                   }

                    serverInfo .setMaxTime((Long) mBeanServer .getAttribute(grpName ,
                              "maxTime" ));
                    serverInfo .setProcessingTime((Long) mBeanServer .getAttribute(
                              grpName, "processingTime" ));
                    serverInfo .setRequestCount((Integer) mBeanServer .getAttribute(
                              grpName, "requestCount" ));
                    serverInfo .setErrorCount((Integer) mBeanServer .getAttribute(
                              grpName, "errorCount" ));
                    serverInfo .setBytesReceived((Long) mBeanServer .getAttribute(
                              grpName, "bytesReceived" ));
                    serverInfo .setBytesSent((Long) mBeanServer .getAttribute(
                              grpName, "bytesSent" ));

                    store.storeInfo( serverInfo );

              }

在server.xml配置好自己定義的listener,啟動tomcat,便能夠看到收集到的數據。如(這裏為了測試。收集到的數據直接寫日誌):

ServerInfo:maxThreads:200,currentThreadCount:16,busyThreadCount:6,keepAliveCount:0,maxTime:6166,requestCount:57,errorCount:0,processTime:10380,bytesRec:0,bytesSend:238874

當然。還有非常多其他的信息能夠收集。看詳細須要。

另外。還能夠借助Value鏈條,編寫自己的Value來上報請求處理時間,異常情況等等。

基礎的代碼可在github上看看:https://github.com/jjmatrix/tomcat-extension


相關的內容:

Tomcat源代碼走讀1:從何開始

Tomcat源代碼走讀2:啟動過程

Tomcat源代碼走讀5:請求處理

Tomcat源代碼走讀——內存泄露檢測






Tomcat擴展——監控