運用JMX遠程監控、管理JVM

問題背景討論:在JAVA運行時,對JVM系統的檢測、管理是開發同學一直期望的,目前有一些開源產品開源針對JVM進行監控,例如javamelody等等,這樣框架雖然好,但是如果使用會帶來一些問題。第一:由於javamelody入口是一個filter,所以會帶來性能問題、第二:如果應用服務器很多,會缺乏統一管理,此外安全性、爬蟲等等問題略過不提
    JDK自帶了故障檢測工具Jconsole和1.6出來的Jvisualvm都可以遠程對服務器進行監控,後者甚是提供可以在線得到ThreadDump和HeapDump文件,更是提供了可擴展插件功能(雖然可能會影響jvm服務器性能)
   但現狀很多公司都有自己的運維團隊,未必會把線上服務器的權限交給我們開發同學,所以有必要了解JAVA遠程管理方面的知識,假設如果在後臺有一套系統,可以管理、監控我們線上所有java服務器,如果出現問題不需要對每個服務器進行排查而是直接從列表中獲取、定位到信息,豈不是一件很幸福的事情~

   書歸正文,分享下近幾天在JMX方面的知識,JDK的API中翻譯過來對javax.management的描述

    提供 Java Management Extensions 的核心類。
    Java Management Extensions (JMXTM) API 是一個用於管理和監視的標準 API。典型用途包括:
      1) 查詢並更改應用程序配置
      2) 累積有關應用程序行爲的統計數據並使其可用
      3) 通知狀態更改及錯誤狀況。
      4) JMX API 還可以作爲解決方案的一部分來管理系統、網絡等。
      5) API 包括遠程訪問,遠程管理程序可以基於這些目的與正在運行的應用程序進行交互。
    JMX核心類爲Mbean。MBean 是表示資源的指定管理對象。它有一個管理接口,該接口包括以下內容:
      1) 可以讀取和/或寫入的指定名稱和類型的屬性  
      2) 可以調用的指定名稱和類型的操作
      3) 可以由 MBean 發送的指定類型的通知。
    推薦一篇文章可以讓大家入門
http://www.ibm.com/developerworks/cn/java/j-lo-jse63/

    配置遠程連接tomcat需要在tomcat所在服務器修改幾個配置
     1) 修改JMX配置
     進入JAVA_HOME/jre/lib/management路徑下面
     將jmxremote.password.template改成jmxremote.password,將內容中的monitorRole  QED的註釋去掉
     將management.properties中的com.sun.management.jmxremote.port=(改成你想要的JMX端口號)
將  com.sun.management.jmxremote.ssl=false、                                                      com.sun.management.jmxremote.authenticate=false註釋打開
    注意:linux下需要該權限,chmod 600 jmxremote.access, chmod 600 jmxremote.password
   window下特麻煩,現需要jdk裝在NTFS文件系統下,選中文件,點右鍵“屬性”-〉安全,點“高級”,去掉“從父項繼承....”,彈出窗口中選“刪除”,這樣刪除了所有訪問權限。再選“添加”-〉高級,“立即查找”,選中你的用戶,例administrator,點“確定",“確定"。來到權限窗口,勾選"完全控制",點"確定",OK了。
    用jconsole連接遠程linux服務時, IP地址和port都輸入正確的情況下,仍然是連接失敗
vi /etc/hosts,將hostname對應的ip改爲真實ip
    2) 修改tomcat啓動參數
    windows下面爲catalina.bat、linux下面爲cataina.sh
   set CATALINA_OPTS=-Dcom.sun.management.jmxremote
   -Dcom.sun.management.jmxremote.port="JMXport"
   -Dcom.sun.management.jmxremote.ssl=false
   -Dcom.sun.management.jmxremote.authenticate=false

    如果不修改的時候默遠程連接不上,遠程連接的通過IP和JMX端口找到JVM虛擬機後無法定位具體哪個應用使用JMX端口,所以只有在啓動tomcat情況後佔用JMX

  關於配置JMX,可以具體參考http://download.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote

  實戰遠程連接TOMCAT
  1) 獲取連接

Java代碼 收藏代碼
  1. privatestaticvoid getConnection() throws Exception {    

  2. //用戶名、密碼  

  3.                 Map<String, String[]> map = new HashMap<String, String[]>();    

  4.    map    

  5.            .put("jmx.remote.credentials", new String[] { "monitorRole",    

  6. "QED" });    

  7.    String jmxURL = "service:jmx:rmi:///jndi/rmi://192.168.0.100:1000/jmxrmi";    

  8.    JMXServiceURL serviceURL = new JMXServiceURL(jmxURL);    

  9.    connector = JMXConnectorFactory.connect(serviceURL, map);    

  10.    mbsc = connector.getMBeanServerConnection();    

  11. }    

 2) 獲取所有的objectName

Java代碼 收藏代碼
  1.   Set MBeanset = mbsc.queryMBeans(null, null);    

  2. Iterator MBeansetIterator = MBeanset.iterator();    

  3. while (MBeansetIterator.hasNext()) {    

  4.    ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator    

  5.            .next();    

  6.    ObjectName objectName = objectInstance.getObjectName();    

  7.    MBeanInfo objectInfo = mbsc.getMBeanInfo(objectName);    

  8.    System.out.print("ObjectName:" + objectName.getCanonicalName()    

  9.            + ".");    

  10.    System.out.print("mehtodName:");    

  11. for (int i = 0; i < objectInfo.getAttributes().length; i++) {    

  12.        System.out.print(objectInfo.getAttributes()[i].getName() + ",");    

  13.    }    

  14.    System.out.println();    

  15. }    


3) 獲取堆內存信息

Java代碼 收藏代碼
  1. ObjectName heapObjName = new ObjectName("java.lang:type=Memory");    

  2. //堆內存  

  3. MemoryUsage heapMemoryUsage = MemoryUsage    

  4. .from((CompositeDataSupport) mbsc.getAttribute(heapObjName,    

  5. "HeapMemoryUsage"));    

  6. long commitMemory = heapMemoryUsage.getCommitted();// 堆當前分配  

  7. long usedMemory = heapMemoryUsage.getUsed();    

  8. System.out.print("堆內存總量:"+heapMemoryUsage.getMax()/1024+"KB,當前分配量:"+commitMemory/1024+"KB,當前使用率:"+usedMemory/1024+"KB,");    

  9. System.out.println("堆內存使用率:" + (int) usedMemory * 100

  10.        / commitMemory + "%");// 堆使用率  

  11. //棧內存  

  12.        MemoryUsage nonheapMemoryUsage = MemoryUsage    

  13.        .from((CompositeDataSupport) mbsc.getAttribute(heapObjName,    

  14. "NonHeapMemoryUsage"));    

  15. long noncommitMemory = nonheapMemoryUsage.getCommitted();    

  16. long nonusedMemory = heapMemoryUsage.getUsed();    

  17. System.out.println("棧內存使用率:" + (int) nonusedMemory * 100

  18.        / noncommitMemory + "%");    

  19. //PermGen內存  

  20.        ObjectName permObjName = new ObjectName(    

  21. "java.lang:type=MemoryPool,name=Perm Gen");    

  22. MemoryUsage permGenUsage = MemoryUsage    

  23.        .from((CompositeDataSupport) mbsc.getAttribute(permObjName,    

  24. "Usage"));    

  25. long committed = permGenUsage.getCommitted();// 持久堆大小  

  26. long used = heapMemoryUsage.getUsed();//    

  27. System.out.println("perm gen:" + (int) used * 100 / committed    

  28.        + "%");// 持久堆使用率


4) 獲取堆中伊甸區

Java代碼 收藏代碼
  1. ObjectName youngHeapObjName = new ObjectName("java.lang:type=MemoryPool,name=Eden Space");    

  2. // 獲取Mbean對象  

  3.    MBeanInfo youngHeapInfo = mbsc.getMBeanInfo(youngHeapObjName);    

  4. // 獲取對象的屬性  

  5.    MBeanAttributeInfo[] youngHeapAttributes = youngHeapInfo.getAttributes();    

  6.    MemoryUsage youngHeapUsage = MemoryUsage    

  7.                .from((CompositeDataSupport) mbsc.getAttribute(youngHeapObjName, "Usage"));    

  8.       System.out.print("目前新生區分 配最大內存:"+youngHeapUsage.getMax()/1024+"KB,");    

  9.       System.out.print("新生區已分配:"+youngHeapUsage.getCommitted()/1024+"KB,");    

  10.       System.out.print("新生區初始化:"+youngHeapUsage.getInit()/1024+"KB,");    

  11.       System.out.println("新生區已使用"+youngHeapUsage.getUsed()/1024+"KB");    


5) 獲取線程

Java代碼 收藏代碼
  1. ObjectName managerObjName = new ObjectName(    

  2. "Catalina:type=Manager,*");    

  3.        Set<ObjectName> s = mbsc.queryNames(managerObjName, null);    

  4. for (ObjectName obj : s) {    

  5.            ObjectName objname = new ObjectName(obj.getCanonicalName());    

  6.            System.out.print("objectName:"+objname);    

  7.            System.out.print(",最大會話數:"

  8.                    + mbsc.getAttribute(objname, "maxActiveSessions")+",");    

  9.            System.out.print("會話數:"

  10.                    + mbsc.getAttribute(objname, "activeSessions")+",");    

  11.            System.out.println("活動會話數:"

  12.                    + mbsc.getAttribute(objname, "sessionCounter"));    


由於可以獲取的信息很多,暫不全部列出來
翻過頭來看下tomcat對JMX的支持


    看完上面最後一段話,有沒有一種很雷人的感覺

    關於tomcat對JMX的支持可以看下詳細的文檔
http://tomcat.apache.org/tomcat-6.0-doc/monitoring.html

    當我們默認直接訪問tomcat提供的JMX接口時(http://localhost:8080/manager/jmxproxy/?qry=)會出現所有的MBeans,



如果想要具體的MBeans只需要將其name後面的值放在url的後面  


 因此,在默認情況下我們看到的信息都可以通過遠程方式獲取到,下一篇會介紹如何遠程管理Tomcat


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章