Tomcat

Tomcat執行緒消耗最大CPU

  • May 24, 2012

我們有一個在 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)

引用自:https://serverfault.com/questions/392157