当前位置: 首页 > 知识库问答 >
问题:

Apache HttpClient PoolighttpClientConnectionManager连接泄漏?

郭逸清
2023-03-14

我正在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个连接被列为“已建立”。我可以看到端口号没有改变。对我来说,这似乎意味着它实际上是在重复使用连接。

但这并不能解释为什么我仍在泄漏代码中的连接?以TIME_WAIT状态显示的重用连接和泄漏连接(在netstat-a中找到)共享相同的基本url。所以他们肯定是有关联的。是否有可能我正在重新使用连接,但不知何故没有正确关闭响应?

编辑3

找到了等待时间“泄漏”的来源。它在一段不相关的代码中。所以这与HttpClient无关。然而,在修复代码之后,所有的等待时间都消失了,但是应用程序在多次点击HttpClient代码时仍然没有响应。还在调查那部分。

共有2个答案

颜华池
2023-03-14

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

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

两点:

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

无论scala的并行特性如何,您都应该了解域池中的5个线程是如何共享套接字的??android/java经验的IMO是,即使每个线程执行器应该在该httpclient.exec语句的范围内对服务器进行阻塞I/O,所涉及的实际通道管理允许非常高的线程,而无需求助于ASNyC客户端库进行超文本传输协议。

Android体验可能与此无关,因为客户端只有4个线程。话虽如此,即使你有64个或更多线程可用,我只是不明白每个域需要超过10个连接才能让你的底层http套接字非常非常繁忙地处理thruput。

何峰
2023-03-14

您应该真正考虑重新使用HttpClient实例,或者至少重新使用支撑它的连接池,而不是为每个新的请求执行创建它们。如果希望继续执行后一种操作,还应在客户端或连接池超出范围之前关闭它们。

就泄漏而言,通过运行应用程序并使用上下文日志记录连接管理,应该可以相对容易地进行跟踪,如下所述

 类似资料:
  • 我正在开发一个在Java服务器上运行的游戏。对于数据库池,我使用的是HikariCP,这是一个优秀的库,但它现在抛出了以下错误: 现在我知道连接泄漏意味着打开的连接在某个地方漂浮,但我不知道如何或在哪里漂浮。 下面是我的数据库类中的一个方法,根据堆栈跟踪,错误应该发生在这里。 这只是启动语句的一个基本方法。调用它时,我使用它,然后调用、和 但它告诉我连接是打开的。 我怎么解决这个?谢了!

  • 我有一个带有和对象的。每次调用,我都会执行以下操作: 我不关闭,因为没有关闭方法。每次调用servlet时,mongo中使用的连接数都会增加: 什么是与mongo和morphia建立联系的正确方式?这种联系到底在哪里?谢谢

  • 我在webapp(hibernate-core-4.3.8。Final和Spring 3.2.11。RELEASE)上使用Spring和hibernate。我使用hikaricp(v 2.2.5)作为连接池impl,它检测连接泄漏并打印下面的stacktrac。我使用Spring的声明性事务划分,因此我假设资源的管理和清理是由Spring/hibernate完成的。因此,我认为Spring或hib

  • 我正在运行一个Spring boot Java应用程序,使用默认的HikariCP作为数据源: Hikari版本-3.4.5 在AWS EKS中运行的Spring Boot version-2.4.5 JDBI版本-3.9.1 DB-AWS RDS Postgres 我的Spring应用程序变得没有响应,因为它失去了Hikari池中的所有连接。这并不是确定地发生,但是一旦它开始发生,唯一可能的恢复

  • 我的连接器类: 连接器。JAVA 这是我的DAO类(简化):UserDAO. java 在这里,我发现了关于Hikari的一些事实的问题: 您必须在HikariCP为您提供的连接实例上调用关闭() 可能是我的不起作用,因为它只是Hikari在方法中提供给我的连接的副本。

  • 我正在尝试识别应用程序中的SQL连接泄漏。经过一些操作后,当我的应用程序处于空闲状态(用户未执行任何活动)时,我在返回的结果集中看到7个与我的数据库的连接。所有连接的状态均为,所有连接的值均为。 我正在使用连接池,但连接字符串中未指定连接生存期。这意味着如果我是对的,将使用它的默认值0。连接生存期的值为零意味着SQL server永远不应该关闭连接,对吗? 我让我的应用程序空闲一段时间(15-20