转自:kafka0102
昨天的搜索系统又出状况了,几个库同时重建索引变得死慢。经过一个上午的复现分析,确定问题出现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给出个明显的最佳实践到能引起使用者的注意,否则误用的情况还是会时有发生。不信,google之。
=============================== 华丽的终止符 ================================
分享到:
相关推荐
通过使用HttpClient的连接池和多线程,我们可以有效地并发执行HTTP GET请求,同时控制并发数量,避免过多的网络连接导致服务器压力过大。这种方式提高了请求效率,减少了资源消耗,并且遵循了最佳实践。
2. 连接管理器升级,提供了更智能的连接池管理,可以更好地控制并发连接数量和超时策略。 3. 支持HTTP/2和SPDY协议,增强了与现代服务器的兼容性。 4. 提供了更多的重试和恢复策略,增强了网络不稳定情况下的健壮性...
- 对于高并发场景,应适当调整连接池参数,如最大连接数、超时时间等。 HttpClient 4.5.5 作为一个成熟的 HTTP 客户端库,不仅提供了丰富的功能,还具有良好的可扩展性和灵活性。开发者可以根据具体需求对其进行...
HttpClient也支持异步操作,通过`HttpAsyncClient`类,可以在回调函数中处理响应,适合于高并发场景。 总的来说,HttpClient是Java中强大的HTTP客户端工具,能够满足各种复杂的HTTP请求需求。其丰富的功能和高度可...
HttpClient是Apache基金会开发的一个Java库,它为Java程序员提供了一个强大的、灵活的、稳定的、功能丰富的客户端HTTP通信框架。...同时,及时关注Apache HttpClient的更新,以便利用新特性并修复已知问题。
1. **多线程支持**:HttpClient 4.2.1支持多线程并发请求,可以高效地处理大量并发连接,提升了处理能力。 2. **连接管理**:它提供了连接池管理,允许重用已建立的TCP连接,减少网络延迟,提高整体性能。 3. **...
使用`MultiThreadedHttpConnectionManager`管理连接,并确保每个请求都有独立的HttpClient实例,或者对共享的HttpClient实例进行适当的同步,避免并发问题。 6. **HTTP协议特性**:服务器可能使用了chunked编码(一...
5. **连接管理**:使用`HttpConnectionManager`管理连接池,控制并发连接数,重用连接。 6. **认证与安全**:实现基本认证、摘要认证,配置SSL/TLS连接,处理证书问题。 7. **性能优化**:使用连接池提高性能,控制...
1. **HTTP/1.1和HTTP/2支持**:HttpClient 4.5.3支持HTTP协议的最新版本,可以处理多路复用连接,提高了并发性能。 2. **连接管理**:HttpClient提供了`HttpConnectionManager`接口,用于管理到服务器的连接。默认...
HttpClient 的功能包括但不限于 HTTP 请求的执行、响应的处理、连接管理、异常处理、协议拦截器以及重定向处理等。 在讨论HttpClient的文档时,首先应该明确它的使用范围,也即HttpClient能够做什么,以及它不做...
10. **线程安全**:为了适应多线程环境,`httpclientUtils`可能已经考虑了HttpClient实例的线程安全问题,确保在并发环境中正确使用。 在实际使用`httpclientUtils`时,开发者可以通过调用工具类提供的方法,如`...
HttpClient允许进行多线程并发请求,但需要注意线程安全问题。此外,合理设置连接超时、重试策略、连接池大小等参数也能显著提升性能。 九、与其他库的集成 HttpClient可以方便地与Spring框架、JUnit测试等结合使用...
8. **多线程请求执行**:HttpClient支持在多线程环境中执行请求,这使得在并发环境中使用HttpClient更加安全。 9. **HTTP状态管理**:HttpClient支持HTTP cookie的管理,包括不同版本的cookie处理、cookie策略选择...
4. 并发处理:在多线程环境中,需正确管理和同步HttpClient实例。 总的来说,Apache Commons HttpClient 3.1是Java开发中处理HTTP通信的强大工具,虽然现在已经有了更新的版本,但3.1版本在许多项目中仍被广泛使用...
- **连接管理**:通过`HttpConnectionManager`,HttpClient可以管理多个并发连接,实现高效的连接复用,降低网络延迟。 - **请求和响应处理**:HttpClient提供了`HttpRequestExecutor`和`HttpResponseHandler`接口...
7. **异步处理**:HttpClient 4.5以上版本提供了异步客户端API,可以并发处理多个请求,提高应用的并发性能。 8. **SSL/TLS支持**:HttpClient可以配置为使用HTTPS协议,需要`httpmime-x.x.x.jar`(处理MIME类型,...
HttpClient 4.5引入了`PoolingHttpClientConnectionManager`,它负责管理连接池,自动回收和复用连接。通过配置最大连接数、每个路由的最大连接数以及连接超时等参数,可以有效控制资源使用。 4. **异步编程支持**...
5. 异步请求:HttpClient提供异步执行请求的功能,可以实现非阻塞I/O,提高并发性能。 五、HttpClient的应用场景 HttpClient广泛应用于Web服务调用、爬虫程序、数据同步、自动化测试等领域。例如,在Web服务API调用...
- **连接管理**:HttpClient提供了高级的连接管理机制,包括连接池(Connection Pooling)和智能重用,有效解决了HTTP连接的创建和关闭问题,提高了性能。 - **认证与安全**:支持多种身份验证机制,如基本认证、...