来自 MarkLogic Java 客户端 API 运行 的 HTTP 连接陷入死锁

HTTP Connections from MarkLogic Java Client API run into deadlock

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

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

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

我正在使用 MarkLogic 服务器 7.0.4 和 Java 1.7(Mac OSX 10.9.5)和 MarkLogic 客户端 API 2.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.getPoolEntry(ConnPoolByRoute.java:298)
    at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.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.access0(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)

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

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

我在 Cookbooks 和文档中看到的示例显示它在关闭之前使用了相当短的时间。

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

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