Apache HttpClient PoolingHttpClientConnectionManager泄漏连接?

时间:2014-04-01 23:08:29

标签: scala apache-httpclient-4.x apache-commons-httpclient spray

我在Scala应用程序中使用Apache Http Client。

应用程序具有相当高的吞吐量和高并行性。

我不确定,但我想也许我正在泄漏关系。似乎只要使用客户端的代码部分变得繁忙,应用程序就会无响应。我的怀疑是我正在泄漏套接字或某些东西,这会导致应用程序的其他方面停止工作。它也可能不会泄漏连接,就像没有足够快地关闭它们一样。

对于更多上下文,偶尔会有某些操作导致此代码并行执行数百次。发生这种情况时,应用程序的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代码时,应用程序仍然没有响应。仍在调查那部分。

2 个答案:

答案 0 :(得分:1)

您应该考虑重新使用HttpClient实例,或者至少使用支持它的连接池,而不是为每个新请求执行创建它们。如果您希望继续执行后者,则还应关闭客户端或关闭连接池,直到它们超出范围。

就泄漏问题而言,通过运行您的应用程序来跟踪连接管理应该相对容易,如上所述here

答案 1 :(得分:0)

IMO - 如果您有效地使用http,则每个域可以使用更少数量的maxConnection(如5而不是50),并且仍然可以完全饱和网络带宽。

我不是scala人(android,java),但在http客户端端口线程池上做了很多很多优化。 IMO - 盲目地将每个域的连接增加到50,这掩盖了其他一些严重的问题。

2分:

如果您正在使用共享的“sharedPoolingClientConnManager”,正确地转到每个域的一个小池,并且您遵循建议的方式将您的conn释放回池中(您应该能够调试所有这些看到的运行指标每个线程池实例的连接状态)那么你应该是好的。

无论scala的并行性功能如何,你都应该了解域中池中5个相应线程如何共享套接字?来自android / java体验的IMO是,即使每个线程执行程序在httpclient.exec语句的范围内对服务器进行阻塞I / O,实际的通道管理也允许非常高的吞吐量,而无需借助ASNyC客户端库HTTP。

Android体验可能不相关,因为客户端只有4个线程。话虽如此,即使您有64个或更多线程可用,我只是不明白每个域需要超过10个连接,以保持您的底层http套接字非常非常忙于吞吐量。