線上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小時以後沒有發現問題,繼續監控