Tomcat
Tomcat執行緒消耗最大CPU
我們有一個在 OpenJDK Server VM(20.0-b11 混合模式)上執行的 Tomcat 7.0.21 伺服器。webapp 在啟動後通常可以執行幾個小時或幾天——典型的 CPU 負載為 1-2%。
在某個時候,tomcat 程序開始消耗 100% 的 CPU。一段時間後,它將消耗 200%,然後是 300%,依此類推(有 4 個處理器)。
我執行了這個命令來確定是哪些執行緒導致了問題:
ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu
…然後從 JVM 得到一個執行緒轉儲
kill -QUIT <processId>
可以預見的是,當 CPU 為 200% 時,有 2 個違規執行緒。它們的堆棧跟踪是相同的:
"http-bio-80-exec-19" daemon prio=10 tid=0x08dcfc00 nid=0x192e runnable [0x442fe000] java.lang.Thread.State: RUNNABLE at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:339) at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:353) at org.apache.jsp.returnBubble_jsp._jspService(returnBubble_jsp.java:343) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:433) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:389) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:333) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:185) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300) - locked <0x6f39c2b0> (a org.apache.tomcat.util.net.SocketWrapper) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:679)
它引用的 jsp 文件 (
returnBubble_jsp.java:343
) 並沒有真正做任何特別的事情 - 每個使用者都經常呼叫它。如果我們查看生成的 java 的第 343 行:out.write("</td></tr>\n");
所以我相當有信心這不是我的 JSP 造成的!請注意,其他違規執行緒中的行號確實會發生變化,但它始終是類似的
out.write
方法。這個執行緒在做什麼?以及如何防止它發生?
非常感謝@Christopher Schultz - 你的評論讓我更仔細地瀏覽了 jsp,你是對的。當你找到它時很簡單。出於興趣,我有這個:
for (int i=0; i<n; i++) { ... myArray[i=3].method(); ... }
“等號”應該是“減號”。可能會教我在我的 IDE 中使用更大的字型!
嘗試禁用 feedFetcher 任務,因為它看起來是另一個可能導致活鎖問題的執行緒;
"Timer-3" daemon prio=10 tid=0x46135400 nid=0x1901 runnable [0x45f69000] java.lang.Thread.State: RUNNABLE at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:327) - locked <0x85153b58> (a java.net.SocksSocketImpl) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:193) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384) at java.net.Socket.connect(Socket.java:546) at java.net.Socket.connect(Socket.java:495) at sun.net.NetworkClient.doConnect(NetworkClient.java:178) at sun.net.www.http.HttpClient.openServer(HttpClient.java:409) at sun.net.www.http.HttpClient.openServer(HttpClient.java:530) - locked <0x851458d8> (a sun.net.www.http.HttpClient) at sun.net.www.http.HttpClient. (HttpClient.java:240) at sun.net.www.http.HttpClient.New(HttpClient.java:321) at sun.net.www.http.HttpClient.New(HttpClient.java:338) at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:935) at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:876) at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:801) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1139) - locked <0x851c9e58> (a sun.net.www.protocol.http.HttpURLConnection) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:654) at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:783) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:748) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:123) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1208) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:525) at org.jdom.input.SAXBuilder.build(SAXBuilder.java:518) at org.jdom.input.SAXBuilder.build(SAXBuilder.java:905) at uk.rock7.tracker.FeedFetcher.run(FeedFetcher.java:73) at java.util.TimerThread.mainLoop(Timer.java:534) at java.util.TimerThread.run(Timer.java:484)