tomcat cpu佔用過高,系統負載高問題跟蹤

線上8核 linux服務器,負載爲8爲正常情況,目前CPU負載過高,最高負載30多,平均負載在20左右,已經持續近一週,具體佔用CPU資源的服務是tomcat_sc,佔用CPU資源高達:720%

  • 使用jconsole去跟蹤

更改catalina.sh 啓動設置:

 $ CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8933 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=$server_ip";

hostname -i 爲127.0.0.1   

測試服務器配置完後,在本機使用jconsole連接,輸入測試服務器帳號密碼即可連上。網上資料說要改hostname,沒有更改hostname也可行

線上先開了服務器端口,又開了 本機端口,telnet可以連上,但jconsole無法連接,查google,說:

the jvm you're trying to connect to actually exposes *two* ports, the one specified via -Dcom.sun.management.jmxremote.port, and some other one. The 2nd one is random, but jconsole wants to connect to it, so if you have a firewall, and you've only opened up the above port, you're hosed.  

 只開放了一個端口就不可以?必須外網服務器所有端口都對內網開放?繼續跟蹤。

jmap jconsole jstack都是java自帶的jmx 問題跟蹤工具, 可以學習一下幫助分析定位內存溢出 程序死鎖之類的程序問題

使用 jmap  查看內存狀況

jmap -histo:live pid

服務自建類的數量並不多

jstack 跟蹤堆棧也沒看出個所以然

繼續jconsole調查  google “jconsole remote set random port to certain” 找到一篇像樣的文章:

 http://www.componative.com/content/controller/developer/insights/jconsole3/

於是寫了servlet去註冊指定端口 未果

在測試機上先試試  寫java文件:

import java.rmi.registry.LocateRegistry;
import javax.management.MBeanServer;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;

public class JmxTest {
public static void main(String[] args) {
MBeanServer mbeanServer =
ManagementFactory.getPlatformMBeanServer();

JMXServiceURL url = null;
try {
url = new JMXServiceURL(
"service:jmx:rmi://localhost:12199/jndi/rmi://localhost:8933/jmxrmi");
} catch (MalformedURLException e) {
  e.printStackTrace();
}

JMXConnectorServer connectorServer =
null;
try {
connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbeanServer);
} catch (IOException e) {
  e.printStackTrace();
}

try {
System.setProperty("java.rmi.server.randomIDs", "true");
LocateRegistry.getRegistry(8933);
connectorServer.start();
} catch (IOException e) {
  e.printStackTrace();  
}

}
}

出現 java.rmi.AccessException: Cannot modify this registry 錯誤

註釋掉  catalina.sh的啓動設置   -Dcom.sun.management.jmxremote.port=8933  也不行

 最終放棄了jconsole

  •       使用 java.lang.management..ThreadMXBean 
    用焱哥轉發 新陽提供的 jsp頁面 分析性能問題,主要是看線程阻塞情況
    主要代碼:
    ThreadMXBean tm = ManagementFactory.getThreadMXBean();
    tm.setThreadContentionMonitoringEnabled(true);
    <%
    long [] tid = tm.getAllThreadIds();
    ThreadInfo [] tia = tm.getThreadInfo(tid, Integer.MAX_VALUE);

    long [][] threadArray = new long[tia.length][2];

    for (int i = 0; i < tia.length; i++) {
    long threadId = tia[i].getThreadId();

    long cpuTime = tm.getThreadCpuTime(tia[i].getThreadId())/(1000*1000*1000);
    threadArray[i][0] = threadId;
    threadArray[i][1] = cpuTime;
    }

    檢測到如下線程問題:
    Thread ID: 89
    Thread Name: http-6080-Processor73
    Thread State: RUNNABLE
    Thread Lock Name: null
    Thread Lock Owner Name: null
    Thread CPU Time: 35678 sec
    Stack Info: (depth:31)
    +java.util.HashMap.get(HashMap.java:303)
    +com.netqin.baike.server.nqrs.CloudSecurityCommand.writePkgsLog(CloudSecurityCommand.java:466)
    +com.netqin.baike.server.nqrs.CloudSecurityCommand.execute(CloudSecurityCommand.java:153)
    +com.netqin.baike.server.BaikeServer.service(BaikeServer.java:64)
    +sun.reflect.GeneratedMethodAccessor33.invoke(Unknown Source)
    CPU佔用時間達到
    35678秒 ,到下午到了50000秒左右,tomcat的CPU佔用達到了200%
    分析代碼,發現是單例bean中使用了 hashmap 作爲類對象,多線程訪問時 類成員hashmap並不是線程安全的 非單例,引起了問題。更正代碼後,截至目前 12小時以後沒有發現問題,繼續監控
發佈了276 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章