httpclient的并发连接问题

昨天的搜索系统又出状况了,几个库同时重建索引变得死慢。经过一个上午的复现分析,确定问题出现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中的:

public static final int DEFAULT_MAX_HOST_CONNECTIONS = 2; // Per RFC 2616 sec 8.1.4 ? 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之。

时间: 2024-10-08 01:28:33

httpclient的并发连接问题的相关文章

C#多线程环境下调用 HttpWebRequest 并发连接限制

.net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 windows xp , windows 7 下默认是2,在服务器操作系统上默认为10. 如果不修改这个并发连接限制,那么客户端同时可以建立的 http 连接数就只有2个或10个.对于一些诸如浏览器或网络蜘蛛的应用,2个或10个并发数量实在太少,大大影响应用的性能.之所以有这个并发连接限制,是因为 http 1.0 和 http 1.1 标准规定并发连接数最大为2. 不

Nginx并发连接限制

转载自:http://www.abc3210.com/2013/web_04/82.shtml HttpLimitReqModul用来限制单位时间内连接数的模块,使用limit_req_zone和limit_req指令配合使用来达到限制.一旦并发连接超过指定数量,就会返回503错误. HttpLimitConnModul用来限制单个ip的并发连接数,使用limit_zone和limit_conn指令. 这两个模块的区别前一个是对一段时间内的连接数限制,后者是对同一时刻的连接数限制. http{

erlang如何有效监听大量并发连接

看了erlang的一些开源网络框架RabbitMQ.Ranch,他们都使用多个进程同时accept一个socket.这种方式在使得socket端口监听的工作分担了更多的调度机会,但是,在erlang中,socket接受一个新连接后,如果想让另一个进程处理消息,就要显式的调用gen_tcp:controlling_process(Socket, Pid). 所以问题来了,erlang多个进程同时监听一个socket安全吗? 这种方式在早期的erlang是不安全的,但R11B03 版本之后,erla

多线程环境下调用 HttpWebRequest 并发连接限制

.net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 windows xp , windows  7 下默认是2,在服务器操作系统上默认为10. 如果不修改这个并发连接限制,那么客户端同时可以建立的 http 连接数就只有2个或10个.对于一些诸如浏览器或网络蜘蛛的应用,2个或10个并发数量实在太少,大大影响应用的性能.之所以有这个并发连接限制,是因为 http 1.0 和 http 1.1 标准规定并发连接数最大为2.

千万并发连接实战

c10k,c100k,c1000k等问题大家都已经司空见惯,那么10m(千万)并发连接呢?今天就来一起挑战一下. 准备机器10m连接,大家的个人电脑肯定无法满足要求,如果不是在大公司任职,弄个实际的物理机对大家是个奢望.那么怎么办?我也面临同样问题.现在的云计算这么发达,还可以按小时计费,一小时的费用也就几元,那就试试云计算产品吧.小编先是在阿里云上测试,但阿里云的按需付费主机配置不高,费了不少时间,最终只跑到了3m个连接.阿里云的不行,是主机的配置问题还是程序的问题呢?为了得到最终的结论,我尝

单机千万并发连接实战

c10k,c100k,c1000k等问题大家都已经司空见惯,那么10m(千万)并发连接呢?今天就来一起挑战一下吧. 准备机器 10m连接,大家的个人电脑肯定无法满足要求,如果不是在大公司任职,弄个实际的物理机对大家是个奢望.那么怎么办?我也面临同样问题. 现在的云计算这么发达,还可以按小时计费,一小时的费用也就几元,那就试试云计算产品吧.小编先是在阿里云上测试,但阿里云的按需付费主机配置不高,费了不少时间,最终只跑到了3m个连接.阿里云的不行,是主机的配置问题还是程序的问题呢?为了得到最终的结论

大并发连接的oracle在Linux下内存不足的问题的分析

大并发连接的oracle在Linux下内存不足的问题的分析 2010-01-28 20:06:21 分类: Oracle 最近一台装有Rhel5.3的40G内存的机器上有一个oracle数据库,数据库的SGA设置为20G,当运行业务时,一个业务高峰期时,发现swap频繁交换,CPU 100%,Load很高,基本体现为内存不足.此时的连接数在600个左右.按内存的计算:每个连接占用内存基本在5M,这样600个连接只占用3G内存,SGA内存20G,操作系统占用内存1G,这样总占用的内存为24G,而总

100万并发连接服务器笔记之Java Netty处理1M连接会怎么样

前言 每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼.  这次使用经常使用的顺手的     netty NIO框架(netty-3.6.5.Final),封装的很好,接口很全面,就像它现在的域名   netty.io,专注于网络IO.  整个过程没有什么技术含量,浅显分析过就更显得有些枯燥无聊,准备好,硬着头皮吧. 测试服务器配置 运行在VMWare Workstation 9中,64位Centos 6

(五)通过select监控多个描述符实现并发连接

概述 本文通过使用select改写之前的服务器程序通过监控多个套接字描述符来实现并发连接并加入了一些机制让程序更加健壮,不过我们所有的实验都是建立在单词发送数据不会超过1024字节,如果超过你需要做特殊处理. 代码实例 描述符就绪条件 套接字准备好读 以下条件满足之一则套接字准备好读 套接字接收缓冲区中的数据长度大于0 该连接读半部关闭,也就是本端的套接字收到FIN,也就是对方已经发送完数据并执行了四次断开的第一次发送FIN,这时候本端如果继续尝试读取将会得到一个EOF也就是得到空. 套接字是一