【问题标题】:Best Practice to Use HttpClient in Multithreaded Environment在多线程环境中使用 HttpClient 的最佳实践
【发布时间】:2010-11-19 20:30:25
【问题描述】:

一段时间以来,我一直在多线程环境中使用 HttpClient。对于每一个线程,在发起连接时,都会创建一个全新的 HttpClient 实例。

最近发现,使用这种方式会导致用户打开的端口过多,大部分连接处于TIME_WAIT状态。

http://www.opensubscriber.com/message/commons-httpclient-dev@jakarta.apache.org/86045.html

因此,不是每个线程都在做:

HttpClient c = new HttpClient();
try {
    c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

我们计划:

[方法 A]

// global_c is initialized once through
// HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager());

try {
    global_c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
}

在正常情况下,global_c 将被 50++ 个线程同时访问。我想知道,这会产生任何性能问题吗? MultiThreadedHttpConnectionManager 是否使用无锁机制来实现其线程安全策略?

如果有 10 个线程在使用 global_c,其他 40 个线程会被锁定吗?

或者,如果我在每个线程中创建一个 HttpClient 的实例,但显式释放连接管理器会更好吗?

[方法 B]

MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
HttpClient c = new HttpClient(connman);
try {
      c.executeMethod(method);
}
catch(...) {
}
finally {
    method.releaseConnection();
    connman.shutdown();
}

connman.shutdown() 会遇到性能问题吗?

对于使用 50++ 线程的应用程序,我可以知道哪种方法(A 或 B)更好吗?

【问题讨论】:

    标签: java apache-commons-httpclient


    【解决方案1】:

    使用 HttpClient 4.5,您可以这样做:

    CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
    

    请注意,这个实现了 Closeable(用于关闭连接管理器)。

    【讨论】:

      【解决方案2】:

      方法A是httpclient开发者社区推荐的。

      详情请咨询http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html

      【讨论】:

      • 如果客户端是全局的,什么时候会在连接管理器上调用“关闭”。
      • 哪些工具/linux命令对调试或“可视化”ConnectionManager的行为有用?我问是因为我们目前在 CLOSE_WAIT 和其他效果中的连接有问题,我们正在努力寻找一种好方法来查看到底发生了什么。
      • @WandMaker 我很确定你会在任何一个程序退出时或者当你完成一些你在一段时间内不需要任何连接的工作时调用shutdown。
      • @Christoph netstat 在这方面做得非常好。 technet.microsoft.com/en-us/sysinternals/bb897437.aspx
      【解决方案3】:

      绝对是方法 A,因为它是池化和线程安全的。

      如果您使用的是 httpclient 4.x,则连接管理器称为 ThreadSafeClientConnManager。有关更多详细信息,请参阅此link(向下滚动到“池连接管理器”)。例如:

          HttpParams params = new BasicHttpParams();
          SchemeRegistry registry = new SchemeRegistry();
          registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
          ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry);
          HttpClient client = new DefaultHttpClient(cm, params);
      

      【讨论】:

      • ThreadSafeClientConnManager 在 4.2 中已弃用,取而代之的是 PoolingClientConnManager
      • 您好,通过这种方法创建的httpclient可以用于维护会话,如stackoverflow.com/questions/5960832/… ...?因为当我尝试时,我无法在不同的请求之间保持会话......
      • 4.3.1 此处:PoolingClientConnManager 已被弃用,取而代之的是 PoolingHttpClientConnectionManager。
      • @DrewStephens 再次被 PoolingClientConnManager 弃用,取而代之的是 PoolingHttpClientConnectionManager
      【解决方案4】:

      我想你会想要使用 ThreadSafeClientConnManager。

      你可以在这里看到它是如何工作的:http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

      或者在内部使用它的AndroidHttpClient

      【讨论】:

      • 奥普斯。没有从 HttpClient 3.x 迁移到 4.x 的计划,因为 3.x 在我的应用程序中已经完美运行了将近 2 年 :)
      • 当然,如果有人来这里谷歌搜索答案:)
      【解决方案5】:

      我对文档的阅读是 HttpConnection 本身不被视为线程安全的,因此 MultiThreadedHttpConnectionManager 提供了一个可重用的 HttpConnections 池,您有一个由所有线程共享的 MultiThreadedHttpConnectionManager 并且只初始化一次。因此,您需要对选项 A 进行一些小的改进。

      MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag
      

      然后每个线程应该为每个请求使用序列,从池中获取连接并在其工作完成时将其放回 - 使用 finally 块可能会很好。 您还应该对池没有可用连接的可能性进行编码并处理超时异常。

      HttpConnection connection = null
      try {
          connection = connman.getConnectionWithTimeout(
                              HostConfiguration hostConfiguration, long timeout) 
          // work
      } catch (/*etc*/) {/*etc*/} finally{
          if ( connection != null )
              connman.releaseConnection(connection);
      }
      

      当您使用连接池时,您实际上不会关闭连接,因此这不应该遇到 TIME_WAIT 问题。这种方法确实假设每个线程不会长时间挂在连接上。请注意,conman 本身处于打开状态。

      【讨论】:

      • 没有实际回答我的问题,哪种方法(A 或 B)更好。
      猜你喜欢
      • 2021-04-27
      • 1970-01-01
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 2015-07-25
      • 2015-06-13
      • 2010-09-05
      相关资源
      最近更新 更多