【问题标题】:Java/jetty does not respond to connections after a period of heavy loadJava/jetty 在一段时间的重负载后不响应连接
【发布时间】:2012-09-12 18:08:07
【问题描述】:

我们的 java servlet 在 Jetty 下运行时遇到了一个非常棘手的问题。它在负载低到中等时运行良好,但当负载达到一定水平时,它会在大约 10-20 分钟后停止响应请求。

如果我们在使用 curl 连接到 java 主进程时跟踪它,我们可以看到它建立连接、接收请求、解析它并执行它通常所做的事情(查询 Solr 服务器、执行一些 MySQL 查询等),但结果永远不会发送回客户端。

当它挂起时,它将无限期地挂起。再多的时间都不会让它“跳出来”,但是如果我们在主 java/jetty 进程下杀死任何随机线程,线程数就会下降,它会再次开始响应请求。

它的外观如下:

# curl http://localhost:8080/some-servlet-url

(Does not respond at this point)

# ps -efL | grep qserv | wc -l
243
# ps -efL | grep qserv | wc -l
243
# ps -efL | grep qserv | wc -l
243

(Number of threads remain seemingly constant)

# kill 29760   <--- random thread under the main java/jetty process
# ps -efL | grep qserv | wc -l
26

(Number of threads immediately decreases sharply)

# curl http://localhost:8080/some-servlet-url
... HTTP response ...

(Responds to connections again)

服务器是一个 m2.2xlarge Amazon EC2 实例,运行 Ubuntu 12.04.1 LTS 和 Jetty 8.1.7.v20120910

$ java -version
java version "1.7.0_07"
OpenJDK Runtime Environment (IcedTea7 2.3.2) (7u7-2.3.2-1ubuntu0.12.04.1)
OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)

我们尝试了几种不同的 java 和 Jetty 版本。我们也尝试过使用 Tomcat 代替 Jetty - 同样的问题。

使用 YourKit 分析应用程序没有显示明显的线程锁定或过多的 CPU 使用率。

有什么想法吗?

编辑:我们能够获得挂起的java进程的堆栈跟踪,看起来所有的http线程都处于这种状态:

"http-bio-8080-exec-5" daemon prio=10 tid=0x00007fe518007800 nid=0x1fc5 in Object.wait() [0x00007fe57934f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076ee9d230> (a org.apache.commons.pool.impl.GenericObjectPool)
        at java.lang.Object.wait(Object.java:503)
        at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:810)
        - locked <0x000000076ee9d230> (a org.apache.commons.pool.impl.GenericObjectPool)
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:95)
        at net.acmecorp.active.QueryResultXMLFormatter.selectBestHitsAndRunDocumentCompletion(QueryResultXMLFormatter.java:362)
        at net.acmecorp.active.QueryResultXMLFormatter.queryResultToXMLRootElement(QueryResultXMLFormatter.java:167)
        at net.acmecorp.active.QueryPrepareAndExecuter.prepareParametersAndExecuteQuery_AndInvokeFormatter(QueryPrepareAndExecuter.java:239)
        at net.acmecorp.servlets.MultiQueryServlet.handle(MultiQueryServlet.java:470)
        at net.acmecorp.servlets.MultiQueryServlet.doGet(MultiQueryServlet.java:85)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
        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:407)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        - locked <0x0000000700dd70d0> (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:722)

   Locked ownable synchronizers:
        - <0x000000076ed40990> (a java.util.concurrent.ThreadPoolExecutor$Worker)

我自己并不是真正的 java 人,所以我无法确切地看到这里出了什么问题,但看起来他们肯定都在等待什么……

【问题讨论】:

  • 这听起来更像是您的应用程序的问题,而不是 Tomcat/Jetty 的问题。它可能是一个正在创建且未取消引用的对象,然后长时间的停顿是 GC 试图重新组织堆。当您杀死线程时,您将释放在该线程中分配的内存。
  • @DanMatthews-Grout,我同意这似乎是这样,但我们已经打开了 GC 日志记录,看不到 GC 和挂起之间的任何联系。此外,据我了解,GC 会导致(有时很长)暂停,但如果我们允许,这个过程将挂起数天。

标签: java ubuntu amazon-ec2 jetty


【解决方案1】:

您有数据库池问题,您的 http 线程都在等待数据库资源释放。这是一个常见的问题,您要么需要增加池中的数据库连接数因此不再是问题,要么您需要使用 QoS 服务(如码头中的 QoSFilter)来限制已进入的请求数用于保护小型数据库池的进程。

现在,您的数据库池已被消耗的原因可能有很多,您可能在应用程序中泄漏了它们(从池中获取它们,使用它们,并且从不返回它们)或者您可能只是拥有太多请求同时进来。或者数据库池库本身存在问题。

无论哪种方式,这都不是码头或 tomcat 问题,而是您的应用程序和数据库之间的资源争用问题。请求进入 jetty 或 tomcat,进入 servlet 域,然后在 servlet 等中等待数据库连接,就这么简单。

【讨论】:

  • 我相信你是对的。直到现在我才看到你的回复,但这正是我们过去几个小时一直在努力的。我们在 MySQL 中增加了 GenericObjectPool.maxActive 和 max_connections。到目前为止,我们还没有出现任何挂起,但交通正在放缓,我们要到明天早上才能确定。当我们得到确认时,我会将其设置为接受的答案。谢谢!
  • 成功了!这可能是一个普遍的问题,但我不得不承认,我们花了好几天的时间来摸不着头脑。我希望在某些日志文件中可以包含有关此的内容。无论如何,非常感谢您的回答。
猜你喜欢
  • 2018-05-24
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
相关资源
最近更新 更多