【问题标题】:Apache HttpClient Connection ManagementApache HttpClient 连接管理
【发布时间】:2023-03-06 11:54:01
【问题描述】:

我试图了解在实现中使用 Apache HttpClient 管理 http 连接的最佳方法(不是我的)。我认为现在实现它的方式是一种浪费,但是由于我对这个库不是很熟悉,所以我想确认一下我的想法。

考虑这种情况:

  • 我在tomcat中有一个webapp,意思是多线程环境。
  • 我需要从 Rest 类访问 Rest WebService。对我的应用的每个请求都会创建一个新的 Rest 类实例,以便调用我需要的服务。

选项 1(当前已实现):Rest 类实例化一个新的 PoolingHttpClientConnectionManager 并发出请求。

就个人而言,我认为这完全是浪费。一次只有一个线程访问管理器的实例。因此,这种方法并没有真正的好处。这实际上是最糟糕的,因为我假设创建这个经理可能很昂贵(?)。因此,实际上我们最终会创建多个 PoolingHttpClientConnectionManager,每个线程一个(每个请求一个)。

选项 2:Rest 类只能将一个 PoolingHttpClientConnectionManager 实例化为一种单例。

然后来自 tomcat 的每个线程将重用相同的连接管理器,并且每个线程只会创建新的 httpClient。 我认为这可以从池中获得所有好处,例如控制连接数量和重用。但我不知道这对管理器是否有用(我的猜测是应该没问题,因为这个连接管理器的全部目的是在多线程环境中工作)。

选项 3:Rest 类可以实例化一个 BasicHttpClientConnectionManager 的新实例。

我试过这个并且工作得很好。这意味着每个线程都有自己的单个连接管理器。即使这个管理器只有一个连接,因为我们每个线程都有一个管理器,所以我们实现了并行执行。

我认为这种方法的缺点是没有限制。因此,如果我的应用收到太多请求,我们每次都会创建一个新管理器,而且我们不会重复使用到同一路由的连接。

如果您能就此事给我任何想法,我将不胜感激。 我见过很多例子,但总是来自主函数的简单例子,并明确地创建线程。没有看到tomcat等应用服务器的例子。

【问题讨论】:

  • 选项 2。您希望尽可能广泛地共享连接。多个池只是浪费连接,因为空闲的不共享。

标签: java apache-httpclient-4.x


【解决方案1】:

选项 2 强烈推荐。

【讨论】:

  • 推荐背后的一些推理将是一个有用的补充:)
【解决方案2】:

根据Apache Commons HTTP Client Documentation,选项2是最明智的。

首先,它说:

从一台主机到另一台主机建立连接的过程是 相当复杂,涉及两个之间的多个数据包交换 端点,这可能非常耗时。的开销 连接握手可能很重要,尤其是对于小型 HTTP 消息。如果打开,可以实现更高的数据吞吐量 连接可以重复用于执行多个请求。

HTTP/1.1 声明 HTTP 连接可以重复用于多个 默认情况下的请求。符合 HTTP/1.0 的端点也可以使用 明确传达他们保留的偏好的机制 连接活动并将其用于多个请求。 HTTP 代理可以 还保持空闲连接活动一段时间,以防万一 后续请求需要连接到同一目标主机。 保持连接活动的能力通常被称为 连接持久性。 HttpClient 完全支持连接 持久性。

因此,在那段之后,我们可以得出结论,是的,每次我们想要发出 HTTP 请求时都实例化 HTTP 连接是一个非常糟糕的主意,而您在问题中所谓的选项 1 并不是最好的方法。

稍后在“池连接管理器”下显示:

PoolingHttpClientConnectionManager 是一个更复杂的实现 管理客户端连接池并能够提供服务 来自多个执行线程的连接请求。连接是 以每条路线为基础汇集。对路由的请求 管理器在池中已经有一个可用的持久连接将 通过从池中租用连接而不是创建连接来提供服务 全新的连接。

因此,阅读本段后,我们可以得出结论,是的,应用程序的所有线程共享一个连接池是有意义的。因此,理想情况下,您将其实例化一次,然后在任何需要获取 HTTP 连接的地方共享它。

最后,关于选项 3,文档说:

BasicHttpClientConnectionManager 是一个简单的连接管理器, 一次只维护一个连接。尽管这堂课是 线程安全的,它应该只被一个执行线程使用。 BasicHttpClientConnectionManager 将努力重用 用于具有相同路由的后续请求的连接。它会, 但是,关闭现有连接并为给定的重新打开它 路由,如果持久连接的路由不匹配 的连接请求。如果连接已经 分配,然后抛出 java.lang.IllegalStateException。

所以,选项 3 是有道理的,但在重用昂贵的资源方面,这听起来并不比选项 2 更好。

【讨论】:

    【解决方案3】:

    实际上,我刚刚阅读了一个与此相关的问题,但在 c# 中,我不是这方面的专家,基本上建议使用选项 2。 为每个连接创建一个新的连接管理器可能会导致性能下降,因为它只为一个新连接创建一个新实例(它可能只是一个请求连接,但实际上并没有使用它,它会耗尽 httpclient 管理器)。这个理由足以让您选择。 这是线程link...的链接

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多