httpclient的并发连接问题
Posted in java on 十一月 20th, 2010 by 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之。
摘自:http://www.kafka0102.com/2010/11/405.html
http://www.docin.com/p-376833238.html//jetty httpclient 分析
相关推荐
3. Jetty:Jetty是一个开源的Java Web服务器和Servlet容器。它轻量级、高效且易于集成。在Android环境中,Jetty可以用于创建嵌入式服务器,这特别适合需要在设备上运行小型HTTP服务的情况。通过将Jetty集成到Android...
HttpClient支持连接池管理,通过`PoolingHttpClientConnectionManager`可以控制并发连接数。同时,可以设置重试策略,如`HttpRequestRetryHandler`,在某些网络问题时自动重试请求。 8. **异步调用**: ...
3. **异常处理**:捕获并处理 HttpClient 异常,确保系统稳定运行。 4. **线程安全**:确保 HttpClient 实例在多线程环境下的安全性,避免并发问题。 四、案例回顾 通过具体案例分析,可以更好地理解 HttpClient ...
import org.eclipse.jetty.client.HttpClient; import org.springframework.http.client.JettyClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; public class ...
3. **网络访问**:Java提供了丰富的API来处理网络通信,如Socket、ServerSocket、HttpURLConnection等。深入理解这些API的用法、线程模型、异步编程和安全通信(SSL/TLS)对于开发网络服务和客户端应用至关重要。...
Tomcat、Jetty等JAVA应用服务器提供了稳定的运行环境,确保了高并发下的性能和稳定性。 **2.3 主要指标及分析** 搜索引擎性能的关键指标包括查询响应时间、召回率和准确率。JAVA的并发处理能力和优化的算法可降低...
在实际项目中,我们可能还会用到诸如HTTP协议库(如Apache HttpClient)、WebSocket库(如Jetty或Netty)等第三方库,它们简化了HTTP和WebSocket通信的实现,并且提供了更多的高级功能,如异步操作和自动重试。...
3. **多线程和并发处理**: - **Thread类**:Java中用Thread类来表示线程,每个线程都有自己的执行路径。 - **Runnable接口**:作为线程目标对象,可以实现Runnable接口并重写run()方法来定义线程执行的任务。 - ...
3. **Jetty**:这是一款轻量级的开源HTTP服务器和Servlet容器,它也提供了HTTP客户端API,可以用于处理HTTP请求和响应。 4. ** Ning Async Http Client**:这是一个异步HTTP客户端,它基于Java NIO,能够处理大量...
7. **第三方库**:有一些开源的Java库可以帮助简化HTTP代理服务器的开发,例如`Jetty`、`Apache HttpClient`和`OkHttp`。这些库提供了更高级的功能,如异步处理、连接池和SSL支持。 8. **性能优化**:对于高并发...
5. **Java NIO(非阻塞I/O)**:NIO提供了新的I/O模型,允许多个连接在同一线程中并发处理,提高了服务器的性能。Selector和Channel是其关键组件。 6. **分布式计算**:在Java中,如Hadoop和Spark等框架实现了大...
3. **部署**:将应用程序部署到服务器,如Tomcat或Jetty等应用服务器。 总之,这个Java实现的即时通信系统涵盖了广泛的Java技术点,从基础语法到高级特性,从网络编程到系统设计,是学习和实践Java技术的好案例。...
- Java提供了Thread类和Runnable接口来实现多线程,以及并发工具类如Semaphore、ExecutorService等,用于优化网络服务的性能和响应速度。 9. **RESTful API设计**: - 使用Java的Jersey或Spring MVC可以创建符合...
使用如Apache HttpClient库可以提高并发性能,而Apache Hadoop或Spark则有助于大数据处理和分布式存储。 7. **合规性与反爬策略**:新闻采集需遵循网站的robots.txt协议,并尊重版权,避免过于频繁的请求导致IP被封...
在Java中,可以使用`HttpURLConnection`或者第三方库如Apache HttpClient来实现HTTP客户端,而服务器端可以使用Servlet API或者Jetty、Netty等服务器框架来处理HTTP请求。 通过非阻塞通信,开发者可以构建高并发的...
Java有多个WebSocket库,如Jetty WebSocket和Tomcat WebSocket API,理解它们的使用是必要的。 4. **NIO(非阻塞I/O)**:Java的NIO库提供了更高效的I/O操作,适用于高并发场景。`Selector`、`Channel`和`Buffer`是...
4. **多线程与并发**:由于网络硬盘可能面临大量并发请求,源码中会使用Java的多线程机制,如Thread类、ExecutorService和并发集合,以提高系统性能并保证响应速度。 5. **Web服务器**:为了提供Web服务,可能使用...
5. **多线程与并发**:为了处理并发的设备连接和视频流,Java的并发API(如ExecutorService、Future、Callable等)会得到广泛应用。 6. **流媒体处理**:Java的JMF(Java Media Framework)或第三方库如Xuggler,可...
3. **多线程编程**:在网络应用中,多线程是常用于并发处理请求的关键技术。`Thread`类和`Runnable`接口是Java多线程的基础,而`ExecutorService`和`Future`接口提供了更高级的线程管理。 4. **网络数据序列化与反...
Erlang是一种面向并发、分布式、容错的编程语言,常用于构建高可用性和高并发性的系统,而Java则是一种广泛应用的通用编程语言,广泛应用于企业级应用开发。描述中提到该示例已经过测试且易于理解,这意味着我们将...