`

httpclient的并发连接问题

    博客分类:
  • java
阅读更多

昨天的搜索系统又出状况了,几个库同时重建索引变得死慢。经过一个上午的复现分析,确定问题出现httpclient的使用上(我使用的是3.1这个被广 泛使用的遗留版本)。搜索系统在重建索引时,是并发多个线程(默认是8个)不停的从PHP客户端取数据(当然,从另一个角度来说,搜索系统是客户 端,PHP端是服务端),取回后放到一个队列里由单独的一个或多个线程更新索引。在测试环境复现发现,对于一个请求,PHP端打印耗时是1-2秒,但搜索 端打印在4-6秒。这种耗时差别也就两种可能性,一个是PHP端返回到搜索端接受完耗时太长,另一个就是搜索端在真正发给PHP端数据前等待了很久。因为 有了之前的jetty7的困顿,起初我怀疑是传输数据的问题。因为请求数据的代码部分我只是简单的使用了httpclient,所以只能从 httpclient着手分析。我想到把PHP端和搜索端的请求起始和结束时间都打出来对照一下,不过在这样做之前我把搜索端的并发请求线程数调到了1, 看下单线程情况下效果如何,结果惊奇地发现PHP端和搜索端的耗时相近。所以,可以确定,是httpclient的并发连接处理上可能存在问题。不消说, 翻开httpclient API中和配置相关的接口,结果找到HttpConnectionManagerParams类中下面两个函数:

	public

 void

 setDefaultMaxConnectionsPerHost(

int

 maxHostConnections)

;


	public

 void

 setMaxTotalConnections(

int

 maxTotalConnections)

;

httpclient在处理请求连接方面使用了连接池,它内部实际上有两种连接池,一种是全局的ConnectionPool,一种是每主机(per- host)HostConnectionPool。参数maxHostConnections就HostConnectionPool中表示每主机可保持 连接的连接数,maxTotalConnections是ConnectionPool中可最多保持的连接数。每主机的配置类是 HostConfiguration,HttpClient有个int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method)方法可以指定使用哪个HostConfiguration,不过多数情况都是不显示指定HostConfiguration,这样 httpclient就用了默认的HostConfiguration=null,也就是说所有的请求可以认为指自同一个主机。如果不设置这两个参 数,httpclient自然会用默认的配置,也就是MultiThreadedHttpConnectionManager中的:

    /** The default maximum number of connections allowed per host */


    public

 static

 final

 int

 DEFAULT_MAX_HOST_CONNECTIONS =

 2

;

   // Per RFC 2616 sec 8.1.4


 
    /** The default maximum number of connections allowed overall */


    public

 static

 final

 int

 DEFAULT_MAX_TOTAL_CONNECTIONS =

 20

;

默认的maxHostConnections大小只有2,也就是说,在我并发8个线程请求数据时,实际上会有6个线程处于等待被调度,这也就解释上面的现 象了。再看看上面的注释,我从http://www.faqs.org/rfcs/rfc2616.html找到从了RFC 2616 sec 8.1.4 Practical Considerations段落的最后一段:

Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.

看这叙述,也就表明人家httpclient设置maxHostConnections为2是有根有据的。不过,这种设置显然适合的是浏览器这种客户端, 但我相信,多数使用httpclient并不希望有这种默认的限制。而它默认的只有20的maxTotalConnections也太有些吝啬了。我后来 浏览solr的客户端server类CommonsHttpSolrServer的代码发现了下面的段落,solr要比我更了解httpclient:

    _httpClient =

 (

client ==

 null

)

 ?

 new

 HttpClient(

new

 MultiThreadedHttpConnectionManager(

)

)

 :

 client;


    if

 (

client ==

 null

)

 {


      // set some better defaults if we created a new connection manager and client


      // increase the default connections


      this

.setDefaultMaxConnectionsPerHost

(

 32

 )

;

  // 2


      this

.setMaxTotalConnections

(

 128

 )

;

 // 20


    }

对于httpclient,特别指出的是它的MultiThreadedHttpConnectionManager,看名字好像是多线程并发请求似的, 其实不是,但它也确实用到了多线程,那是在发现连接不够用时起个等待线程wait信号,这个名称的含义应该是多线程情况线程安全的 HttpConnectionManager。
使用httpclient还有两点经验,一个是创建的MultiThreadedHttpConnectionManager 实例最好是全局的,否则会有多个连接池,而HttpClient是线程安全的,可以多个实例。另一个是,在处理请求的最后,也就是finnaly里中,要 调用method.releaseConnection();回收连接,否则连接池就可能会爆了。

补充:写完之后倒在床上,我又想起了几个问题,这里补充上:
1、系统原先重建索引隐约记得速度还是可以的,为什么现在变慢得如此明显?这有两方面的原因,一个是原来系统取数据是用的单线程(我后来发现单取数据取数 据速度跟不上更新索引的速度所以改成多线程),另一个是,当时重建没有一下子同时开启数个库。所以,即便是同样的代码,环境变了,效果也可能变了。当这种 改变悄然发生了,程序员却没有捕捉到,才会第一直觉感到问题的诡异。
2、对于长时间不能获得连接的情况,httpclient是否有warn日志报出来?因为我使用了httpclient的 getResponseBodyAsStream方法,而它会打出warn日志,所以我是关掉了httpclient的warn级别的。所以,我又检查了 httpclient的代码,可惜没看到相关warning log,这点httpclient可以改进下。不过httpclient现在都是4时代了,而我使用的还是3.1的,而3.x已经被停止更新了,所以再采 用httpclient可以考虑4版本的,尽管现在能见到的代码几乎都是用的3.x系列的。
3、httpclient的文档是否有特别提到连接数配置的情况?我翻看了一下,确实在关于threading一页中有提到。不过,我等使用它时显然没有完整阅毕它的文档。

 

多线程编程

HttpClient 中使用多线程的一个主要原因是可以一次执行多个方法。在执行期间,每一个方法都使用一个 HttpConnection 实例。 由 于在同一时间多个连接只能安全地用于单一线程和方法和有限的资源,我们就必须确保连接分配给正确的方法。而 MultiThreadedHttpConnectionManager 完全可以代替我们完成这一项工作,这样我们就不必去考虑多线程带来安全的问题。

MultiThreadedHttpConnectionManager connectionManager =

                 new MultiThreadedHttpConnectionManager();

          HttpClient client = new HttpClient(connectionManager);

以上代码中的 HttpClient 就在多线程中执行多个方 法了。当我们再次调用 httpClient.executeMethod() 方法时,就会去 Connection Manager 中去请求 HttpConneciton 的实例,这样就避免了线程安全问题,因为 HttpClient 已经帮我们做了。

 

Options

 

MultThreadedHttpConnectionManager 参数配置:

 

connectionStaleCheckingEnabled :这个标志对所有已经创建的 connections 都适用。除特殊情况外,此值应该设置成 true

maxConnectionsPerHost :最大连 接数,默认是 2

maxTotalConnections :最大活动连 接数,默认是 20

 

释放连接

 

connection management 比较重要 的是当连接不再使用时,一定要手动释放。这样做的原因是 HttpClient 不能够确定哪个方法不被使用,哪个方法还在使用。这是因为 Response body 不是由 HttpClient 来自动读取其数据的,而是由使用 HttpClient 的应用程序来完成的。当读取 Response 的数据是时,必须使用此方法的连接。这样,在 Response 的数据在读取前, HttpClient 是没有释放连接的。所有这就要求 在读取完 Response 的数据后,应用程序及时的使用 releaseConnection ()方法来释放连接。

 

MultiThreadedHttpConnectionManager connectionManager =

                 new MultiThreadedHttpConnectionManager();

          HttpClient client = new HttpClient(connectionManager);

                     ...

        // and then from inside some thread executing a method

        GetMethod get = new GetMethod(“http://httpcomponents.apache.org/“);

        try {

            client.executeMethod(get);

            // print response to stdout

            System.out.println(get.getResponseBodyAsStream());

        } finally {

            // be sure the connection is released back to the connection

            // manager

            get.releaseConnection();

        }

 

特别注意, 无论执行的方法或是否也不例外被抛出。对于每一个 HttpClient.executeMethod 方法必须有一个 method.releaseConnection )来释放连接。

分享到:
评论
1 楼 burningblood 2015-02-10  
最近也遇到了这个细节问题。我用的是4,里面没有 get.releaseConnection()。
realseConnection在新版中作为ConnManager.realseConnection(con...)的方法了。这个释放操作在execute之后自动执行了,自己不需要去释放。之后当不需要再使用httpclient时,调用shutdown关闭整个连接池。

相关推荐

    使用java的HttpClient实现多线程并发

    通过使用HttpClient的连接池和多线程,我们可以有效地并发执行HTTP GET请求,同时控制并发数量,避免过多的网络连接导致服务器压力过大。这种方式提高了请求效率,减少了资源消耗,并且遵循了最佳实践。

    httpclient4.5.5所有包

    - 对于高并发场景,应适当调整连接池参数,如最大连接数、超时时间等。 HttpClient 4.5.5 作为一个成熟的 HTTP 客户端库,不仅提供了丰富的功能,还具有良好的可扩展性和灵活性。开发者可以根据具体需求对其进行...

    httpclient

    HttpClient也支持异步操作,通过`HttpAsyncClient`类,可以在回调函数中处理响应,适合于高并发场景。 总的来说,HttpClient是Java中强大的HTTP客户端工具,能够满足各种复杂的HTTP请求需求。其丰富的功能和高度可...

    httpClient需要的jar包

    HttpClient是Apache基金会开发的一个Java库,它为Java程序员提供了一个强大的、灵活的、稳定的、功能丰富的客户端HTTP通信框架。...同时,及时关注Apache HttpClient的更新,以便利用新特性并修复已知问题。

    httpclient4.2.1.zip

    1. **多线程支持**:HttpClient 4.2.1支持多线程并发请求,可以高效地处理大量并发连接,提升了处理能力。 2. **连接管理**:它提供了连接池管理,允许重用已建立的TCP连接,减少网络延迟,提高整体性能。 3. **...

    org.apache.commons.httpclient

    5. **连接管理**:使用`HttpConnectionManager`管理连接池,控制并发连接数,重用连接。 6. **认证与安全**:实现基本认证、摘要认证,配置SSL/TLS连接,处理证书问题。 7. **性能优化**:使用连接池提高性能,控制...

    httpclient-4.5.3中文版文档,很实用

    1. **HTTP/1.1和HTTP/2支持**:HttpClient 4.5.3支持HTTP协议的最新版本,可以处理多路复用连接,提高了并发性能。 2. **连接管理**:HttpClient提供了`HttpConnectionManager`接口,用于管理到服务器的连接。默认...

    httpClient官方文档

    HttpClient 的功能包括但不限于 HTTP 请求的执行、响应的处理、连接管理、异常处理、协议拦截器以及重定向处理等。 在讨论HttpClient的文档时,首先应该明确它的使用范围,也即HttpClient能够做什么,以及它不做...

    httpclient4.3工具类

    10. **线程安全**:为了适应多线程环境,`httpclientUtils`可能已经考虑了HttpClient实例的线程安全问题,确保在并发环境中正确使用。 在实际使用`httpclientUtils`时,开发者可以通过调用工具类提供的方法,如`...

    httpclient3.1 javadoc chm版

    HttpClient允许进行多线程并发请求,但需要注意线程安全问题。此外,合理设置连接超时、重试策略、连接池大小等参数也能显著提升性能。 九、与其他库的集成 HttpClient可以方便地与Spring框架、JUnit测试等结合使用...

    HttpClient

    8. **多线程请求执行**:HttpClient支持在多线程环境中执行请求,这使得在并发环境中使用HttpClient更加安全。 9. **HTTP状态管理**:HttpClient支持HTTP cookie的管理,包括不同版本的cookie处理、cookie策略选择...

    httpclient-4.5.3.zip

    - **连接管理**:通过`HttpConnectionManager`,HttpClient可以管理多个并发连接,实现高效的连接复用,降低网络延迟。 - **请求和响应处理**:HttpClient提供了`HttpRequestExecutor`和`HttpResponseHandler`接口...

    commons-httpclient-3.1jar包

    4. 并发处理:在多线程环境中,需正确管理和同步HttpClient实例。 总的来说,Apache Commons HttpClient 3.1是Java开发中处理HTTP通信的强大工具,虽然现在已经有了更新的版本,但3.1版本在许多项目中仍被广泛使用...

    使用HttpClient必须的jar包

    7. **异步处理**:HttpClient 4.5以上版本提供了异步客户端API,可以并发处理多个请求,提高应用的并发性能。 8. **SSL/TLS支持**:HttpClient可以配置为使用HTTPS协议,需要`httpmime-x.x.x.jar`(处理MIME类型,...

    httpclient4.5 jar包

    HttpClient 4.5引入了`PoolingHttpClientConnectionManager`,它负责管理连接池,自动回收和复用连接。通过配置最大连接数、每个路由的最大连接数以及连接超时等参数,可以有效控制资源使用。 4. **异步编程支持**...

    httpclient-4.5.3官方API中文文档_最新译版_2886K

    5. 异步请求:HttpClient提供异步执行请求的功能,可以实现非阻塞I/O,提高并发性能。 五、HttpClient的应用场景 HttpClient广泛应用于Web服务调用、爬虫程序、数据同步、自动化测试等领域。例如,在Web服务API调用...

    HttpClient-4.3.6

    - **连接管理**:HttpClient提供了高级的连接管理机制,包括连接池(Connection Pooling)和智能重用,有效解决了HTTP连接的创建和关闭问题,提高了性能。 - **认证与安全**:支持多种身份验证机制,如基本认证、...

    httpclient-4.5.3 api 中文版

    1. **连接管理**:HttpClient 提供了`HttpClientConnectionManager`接口,用于管理HTTP连接。这个接口的实现,如`PoolingHttpClientConnectionManager`,允许复用HTTP连接,提高性能并减少服务器负载。你可以通过...

    httpclient-4.5jar包

    2. 连接管理器升级,提供了更智能的连接池管理,可以更好地控制并发连接数量和超时策略。 3. 支持HTTP/2和SPDY协议,增强了与现代服务器的兼容性。 4. 提供了更多的重试和恢复策略,增强了网络不稳定情况下的健壮性...

Global site tag (gtag.js) - Google Analytics