【发布时间】:2014-04-11 00:12:51
【问题描述】:
我在 Scala 应用程序中使用 Apache Http 客户端。
该应用程序具有相当高的吞吐量和高并行性。
我不确定,但我想我可能正在泄漏连接。似乎每当使用客户端的代码部分变得繁忙时,应用程序就会变得无响应。我怀疑我正在泄漏套接字或导致应用程序的其他方面停止工作的东西。它也可能不是泄漏连接,而是没有足够快地关闭它们。
对于更多上下文,有时,某些操作会导致此代码每分钟并行执行数百次。发生这种情况时,应用程序的 Rest API (Spray) 变得无响应。应用程序的其他区域也以高并行度运行,并且不会导致应用程序响应性出现问题。
减少这部分代码的并行性似乎确实可以缓解问题,但不是一个可行的长期解决方案。
是我忘记配置了,还是配置不正确?
我使用的代码是这样的:
class SomeClass {
val connectionManager = new PoolingHttpClientConnectionManager()
connectionManager.setDefaultMaxPerRoute(50)
connectionManager.setMaxTotal(500)
val httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()
def postData() {
val post = new HttpPost("http://SomeUrl") // Typically this URL is fixed. It doesn't vary much if at all.
post.setEntity(new StringEntity("Some Data"))
try {
val response = httpClient.execute(post)
try {
// Check the response
} finally {
response.close()
}
} finally {
post.releaseConnection()
}
}
}
编辑
我可以看到我在 TIME_WAIT 状态下建立了很多连接。我尝试将 DefaultMaxPerRoute 和 MaxTotal 调整为各种值,但没有明显效果。似乎我遗漏了一些东西,因此连接没有被重新使用,但我找不到任何表明我遗漏的文档。重用这些连接至关重要。
编辑 2
通过进一步调查,使用 lsof -p,我可以看到,如果我将 MaxPerRoute 设置为 10,实际上有 10 个连接被列为“ESTABLISHED”。我可以看到端口号没有改变。在我看来,这似乎意味着它实际上是在重用连接。
这不能解释为什么我仍然在这段代码中泄漏连接?以 TIME_WAIT 状态显示的重用连接和泄漏连接(使用 netstat -a 找到)共享相同的基本 url。所以它们肯定是相关的。是否有可能我正在重新使用连接,但不知何故没有正确关闭响应?
编辑 3
找到TIME_WAIT“泄漏”的来源。它位于不相关的代码部分中。所以这与 HttpClient 没有任何关系。然而,在修复该代码后,所有 TIME_WAIT 都消失了,但应用程序在多次点击 HttpClient 代码时仍然变得无响应。仍在调查那部分。
【问题讨论】:
-
要分析为什么你的 spray 应用程序变得无响应(如果你认为这可能是一个问题),你可能需要收集一些堆栈跟踪来查看 Akka/spray 线程在哪里花费时间。在控制台上使用
jps和jstack来执行此操作。随时在喷雾邮件列表上发布有关它的信息。
标签: scala apache-httpclient-4.x apache-commons-httpclient spray