Tomcat 线程消耗最大 CPU

Tomcat 线程消耗最大 CPU

我们有一台在 OpenJDK Server VM(20.0-b11 混合模式)上运行的 Tomcat 7.0.21 服务器。Web 应用程序在启动后通常可以运行几个小时或几天 - 典型的 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方法总是类似的。

这个线程在做什么?我该如何防止这种情况发生?

答案1

尝试禁用 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)

答案2

非常感谢@Christopher Schultz - 您的评论让我更仔细地浏览了 jsp,您说得对。找到它很简单。出于兴趣,我有这个:

for (int i=0; i<n; i++) { 
    ...
    myArray[i=3].method();
...
}

“等号”应该是“减号”。也许可以教我在 IDE 中使用更大的字体!

相关内容