【问题标题】:HTTP Connections from MarkLogic Java Client API run into deadlock来自 MarkLogic Java 客户端 API 的 HTTP 连接遇到死锁
【发布时间】:2015-03-23 15:40:08
【问题描述】:

在对我们基于 Java 的中间件通过 Java 客户端 API 访问 MarkLogic 服务器进行压力测试后,我在无法打开更多 HTTP 连接并发生死锁情况的情况下运行。我正在使用一个DatabaseClient 共享实例,但在每个请求上创建一个JSONDocumentManager(带有一个JacksonHandle 用于阅读,没有处理特定的关闭问题)。可能存在连接未正确关闭的问题,还是我必须自己处理?

通过查看无法处理更多连接的netstat,我确实看到FIN_WAIT_2 中有109 个到MarkLogic 服务器(在localhost:8040 上运行)的连接:

ffffff8045f765a0 31c91c01 tcp4       0      0  localhost.8040     localhost.65396    FIN_WAIT_2 

CLOSE_WAIT 中相同数量 (109) 的 TCP 连接:

ffffff804ff83400 73965e73 tcp4       0      0  localhost.49286    localhost.8040     CLOSE_WAIT

我正在使用带有 Java 1.7 (Mac OSX 10.9.5) 和 MarkLogic 客户端 API 2.0.4 的 MarkLogic 服务器 7.0.4。这是线程转储的第一部分(有 10 个类似的线程似乎在等待服务器响应):

"http-nio-8080-exec-10" #31 daemon prio=5 os_prio=31 tid=0x00007fc61f344000 nid=0x7c03 waiting on condition [0x00000001265bb000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007a59cfff8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at org.apache.http.impl.conn.tsccm.WaitingThread.await(WaitingThread.java:159)
    at org.apache.http.impl.conn.tsccm.ConnPoolByRoute.getEntryBlocking(ConnPoolByRoute.java:398)
    at org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1.getPoolEntry(ConnPoolByRoute.java:298)
    at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1.getConnection(ThreadSafeClientConnManager.java:238)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:423)
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:115)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
    at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:170)
    at com.marklogic.client.impl.DigestChallengeFilter.handle(DigestChallengeFilter.java:34)
    at com.sun.jersey.api.client.filter.HTTPDigestAuthFilter.handle(HTTPDigestAuthFilter.java:493)
    at com.sun.jersey.api.client.Client.handle(Client.java:648)
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
    at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
    at com.marklogic.client.impl.JerseyServices.getDocumentImpl(JerseyServices.java:612)
    at com.marklogic.client.impl.JerseyServices.getDocument(JerseyServices.java:568)
    at com.marklogic.client.impl.DocumentManagerImpl.read(DocumentManagerImpl.java:270)
    at com.marklogic.client.impl.DocumentManagerImpl.read(DocumentManagerImpl.java:204)
    at com.marklogic.client.impl.DocumentManagerImpl.read(DocumentManagerImpl.java:164)
    at com.acme.dashboard.service.ReportMetadataRepository.getByName(ReportMetadataRepository.java:64)

为了更好的可读性,省略了堆栈跟踪的更多细节。 在查看 JerseyServices 之后,我还尝试调整以下系统属性(不幸的是没有任何改进):

com.marklogic.client.maximumRetrySeconds: 3 (default: 120)
com.marklogic.client.minimumRetries: 3 (default: 8)

【问题讨论】:

  • netstat 显示什么?
  • @EJP 大约 220 个连接(其中一半处于状态 FIN_WAIT_2,另一半处于 CLOSE_WAIT,请参阅我的第二和第三段;)
  • 你能分享你传递给 JSONDocumentManager.read 的句柄吗?如果它是流式句柄(带有 close() 方法的句柄),您需要确保在完成后关闭句柄。
  • 您是否面临死锁场景?例如,如果请求停止,线程是否永远不会完成?还是您只是向我们展示了许多并发请求期间的快照?
  • @SamMefford 我正在使用JacksonHandleTuplesHandle,它们似乎都没有可用的关闭方法。是的,我遇到了僵局(让我在我的问题中澄清这一点)。谢谢。

标签: java multithreading jersey marklogic jersey-client


【解决方案1】:

听起来您可能遇到了 JacksonHandle 和 TuplesHandle 未关闭其连接的错误(github 问题 #89)。这已在 Java Client API 2.0.5 中修复。您是否能够在 7.0-5 的 ML Server 实例上运行测试并使用 2.0.5 版本的 Java Client API?

【讨论】:

  • 非常感谢,山姆!不幸的是,生产服务器需要一些时间才能更新,您能否确认使用 Java Client API 2.0.5 和 MarkLogic 服务器 7.0-4 能够工作?
  • 我现在已经使用客户端 API 2.0.5 和服务器 7.0-4 对我们的应用程序进行了压力测试,它确实可以成功运行(正确关闭 HTTP 连接)。再次感谢@sam-mefford
【解决方案2】:

出现 FIN_WAIT 和 CLOSE_WAIT 中的套接字的原因有很多,包括内核问题(已知)。

我将开始从头到尾查看单个连接,以确保它正在关闭套接字并且服务器也在关闭 - 如果双方都关闭连接,您应该会很快看到状态从 FIN_WAIT 转换为空。
一个常见问题是不关闭连接的代码路径。你不能指望 GC 这样做,它最终会完成对象,但通常不够快。 检查以确认您正在发布 DatabaseClient。 你打开它多久?

我在 Cookbooks 和 docs 中看到的示例表明它在关闭之前的使用时间相当短。

还要检查您的线程数与服务器端口上配置的线程数。如果您要发送更多并发请求,则服务器已配置为,那么您可以使用单个客户端达到这样的死锁状态。

【讨论】:

  • 感谢您的帮助,实际上我只为所有请求使用了一个 DatabaseClient 实例(我认为它是线程安全的,并且从 javadoc 状态来看,资源昂贵)。我没有处理任何关闭搜索句柄的问题。查询/文档管理器,因为他们的 API 似乎不需要它,至少到目前为止我是这样理解的。
  • 我看看服务器配置,也增加日志看看MarkLogic的ErrorLog是否会指出一些有趣的点来跟进......
猜你喜欢
  • 2019-04-26
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 1970-01-01
  • 2017-03-25
  • 2018-10-07
  • 1970-01-01
相关资源
最近更新 更多