经过一些压力测试,我们基于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
我正在使用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$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)
听起来您可能遇到了JacksonHandle和TuplesHandle未关闭连接的错误(github问题#89)。此问题已在Java客户端API 2.0.5中修复。您是否能够在ML Server的7.0-5实例上运行测试,并使用Java Client API的2.0.5版本?
FIN_WAIT和CLOSE_WAIT中的套接字可能由于多种原因而出现,包括内核问题(已知)。
我会从开始到结束查看单个连接,以确保它正在关闭套接字,并且服务器也在关闭——如果双方都关闭连接,您应该会很快看到从FIN_WAIT到无的状态转换
一个常见的问题是无法关闭连接的代码路径。你不能指望GC这样做,它最终会完成对象,但通常还不够快。检查以验证您是否正在释放DatabaseClient。你开多久?
我在烹饪书和文档中看到的例子表明,在关闭之前,它的使用时间相当短。
还要检查您的线程数与服务器端口上配置的线程数。如果您发送更多并发请求,则服务器配置为,然后您可以使用单个客户端达到这样的死锁状态。