HttpClient优化

HttpClient优化

作者: 郭伟伟  分类: Java技术原创文章  发布时间: 2011-11-07 21:53  ė120,682 views  64条评论

最近的一个项目中需要用HttpClient请求多台远程服务器。由于接口调用有点频繁,结果出现了很多ConnectTimeoutException,于是对程序进行了优化。

业务逻辑的优化和减少请求次数的优化就不说了,下面重点说说HttpClient的优化。

先看看以前的代码,每次请求都会创建一个HttpClient,代码如下:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
HttpClient client = getHttpClient( 5000 , 5000 );
 
GetMethod getMethod = new GetMethod(url);
 
getMethod.setQueryString(parameter);
 
byte [] responseBody = null ;
 
try {
 
     int statusCode = client.executeMethod(getMethod);
 
     if (statusCode != HttpStatus.SC_OK) {
 
         logger.error( "error !" + url + ",statusCode " + statusCode);
 
     }
 
     responseBody = getMethod.getResponseBody();
 
} catch (IOException e) {
 
     logger.error( "error!" + url, e);
 
} finally {
 
    getMethod.releaseConnection();
 
}

这是最简单的代码,很多例子就是这样开始的,如果少量请求还行,请求很频繁的话,这样的代码不是很好。(注意这里连接用完后必须释放连接)。

首先,HttpClient可以共用,减少创建HttpClient的开销。当然,如果你的应用调用HttpClient并不怎么频繁的话那就没必要共用了,毕竟在内存中维护一个空闲的httpClient对象是不保险的。

其次,Connection可以重用,减少建立连接的开销。

要完成以上两点,可以用多线程下的MultiThreadedHttpConnectionManager管理HttpConnection和HttpClient。MultiThreadedHttpConnectionManager管理的HttpClient是线程安全的,可以做成单例的。但是值得注意的是每个线程应该有自己的HttpMethod和HttpState、HttpConfiguration,以区分每次请求的host和HttpSession 。如下所示:

定义好后,在静态块中初始化相关参数

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
static {             
 
     //每主机最大连接数和总共最大连接数,通过hosfConfiguration设置host来区分每个主机 
 
     client.getHttpConnectionManager().getParams().setDefaultMaxConnectionsPerHost(8);
 
     client.getHttpConnectionManager().getParams().setMaxTotalConnections(48);
 
     client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
 
     client.getHttpConnectionManager().getParams().setSoTimeout(5000);
 
     client.getHttpConnectionManager().getParams().setTcpNoDelay( true );
 
     client.getHttpConnectionManager().getParams().setLinger(1);                  
 
     //失败的情况下会进行3次尝试,成功之后不会再尝试
 
     client.getHttpConnectionManager().getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
 
}

HttpConfiguration中有一些参数对提高性能有一些帮助,主要说明如下:

DefaultMaxConnectionsPerHost参数定义每台主机允许的最大连接数,默认为2。这个参数只能用于一些特定的httpConnectionManager,比如MultiThreadedHttpConnectionManager。

MaxTotalConnections参数表示httpConnectionManager管理的最大连接数,默认为20。同上个参数,这个参数也只是在某些特定的httpConnectionManager中有用。

setTcpNoDelay(true)设置是否启用Nagle算法,设置true后禁用Nagle算法,默认为false(即默认启用Nagle算法)。Nagle算法试图通过减少分片的数量来节省带宽。当应用程序希望降低网络延迟并提高性能时,它们可以关闭Nagle算法,这样数据将会更早地发送,但是增加了网络消耗。

setLinger(1)设置socket延迟关闭时间,单位为s,值为0表示这个选项是关闭的,值为-1表示使用JRE的默认设置。

setStaleCheckingEnabled(true)参数设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间[3]

然后,在每个线程代码中,创建自己的HttpMethod。

还有一个很重要的优化点是采用请求/响应实体流,尤其是在请求频繁数据量大的情况下,很大的实体不会被缓存在内存中而直接发送或接收,采用流能有效的提高性能。虽然这些实体可以是字符串或者字节数组,但是它们容易导致内存泄露,你得小心的使用他们,因为它们是整个实体缓存在内存中的。

对于响应流,采用method的getResponseBodyAsStream()来代替getResponseBody() 和getResponseBodyAsString().如下所示:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
HttpClient httpclient = new HttpClient();
 
   GetMethod httpget = new GetMethod( "http://www.myhost.com/" );
 
   try {
 
     httpclient.executeMethod(httpget);
 
     Reader reader = new InputStreamReader(httpget.getResponseBodyAsStream(), httpget.getResponseCharSet());
 
     // consume the response entity
 
   } finally {
 
     httpget.releaseConnection();
 
   }

而对于请求流,可以通过实现RequestEntity自定义自己的各种流,httpclient包含了常见的几种实现,如FileRequestEntity、ByteArrayRequestEntity、StringRequestEntity、MultipartRequestEntity等。使用示例如下:

?
1
2
3
4
5
File myfile = new File( "myfile.txt" );
 
PostMethod httppost = new PostMethod( "/stuff" );
 
httppost.setRequestEntity( new FileRequestEntity(myfile));

如果客户端和服务器的通讯不需要保持会话状态的话,可以通过禁用Cookie来提高一点点性能,比如蜘蛛爬虫之类应用。如下:

?
1
2
3
4
5
HttpMethod method = new GetMethod();
 
method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
 
method.setRequestHeader( "Cookie" , "special-cookie=value" );

参考资料:

1. http://hc.apache.org/httpclient-3.x/performance.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值