HttpClient连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection异常排查_第1页
HttpClient连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection异常排查_第2页
HttpClient连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection异常排查_第3页
HttpClient连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection异常排查_第4页
HttpClient连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection异常排查_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

HttpClient 连接池抛出大量ConnectionPoolTimeoutExceptionTimeoutwaitingforconnection 异常排查今天解决了一个 HttpClient 的异常,汗啊,一个HttpClient 使用稍有不慎都会是毁灭级别的啊。这里有之前因为route配置不当导致服务器异常的一个处理: 里面的HttpConnectionManager 实现就是我在这里使用的实现。问题表现:tomcat后台日志发现大量异常 [plain]viewoutException:Timeoutwaitingforconnection时间一长tomcat就无法继续处理其他请求,从假死变成真死了。linux运行:[plain]viewplaincopyprint?netstat-n|awk'/^tcp/{++S[$NF]}END{for(ainS)printa,S[a]}' 发现CLOSE_WAIT 的数量始终在 400以上,一直没降过。问题分析:一开始我对我的 HttpClient 使用过程深信不疑,我不认为异常是来自这里。所以我开始从 TCP的连接状态入手,猜测可能导致异常的原因。 以前经常遇到 TIME_WAIT数过大导致的服务器异常, 很容易解决,修改下sysctl就ok了。但是这次是 CLOSE_WAIT,是完全不同的概念了。关于TIME_WAIT 和CLOSE_WAIT 的区别和异常处理我会单独起一篇文章详细说说我的理解。简单来说CLOSE_WAIT 数目过大是由于被动关闭连接处理不当导致的。我说一个场景,服务器A会去请求服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完资源后服务器 A会主动发出关闭连接的请求,这个时候就是主动关闭连接,连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设请求的资源服务器B上并不存在,那么这个时候就会由服务器 B发出关闭连接的请求,服务器A就是被动的关闭了连接, 如果服务器 A被动关闭连接之后自己并没有释放连接,那就会造成CLOSE_WAIT 的状态了。所以很明显,问题还是处在程序里头。先看看我的HttpConnectionManager实现:[java]viewplaincopyprint?publicclassHttpConnectionManager{privatestaticHttpParamshttpParams;privatestaticClientConnectionManagerconnectionManager;/***最大连接数*/publicfinalstaticintMAX_TOTAL_CONNECTIONS=800;/***获取连接的最大等待时间*/publicfinalstaticintWAIT_TIMEOUT=60000;/***每个路由最大连接数*/publicfinalstaticintMAX_ROUTE_CONNECTIONS=400; /**连接超时时间 */ publicfinalstaticintCONNECT_TIMEOUT=10000; /**时时间 */ publicfinalstaticintREAD_TIMEOUT=10000; static{ httpParams=newBasicHttpParams();

**读取超设置最大连接数ConnManagerParams.setMaxTotalConnections(httpParams,MAX_TOTAL_CONNECTIONS); //设置获取连接的最大等待时间ConnManagerParams.setTimeout(httpParams,WAIT_TIMEOUT); //设置每个路由最大连接数ConnPerRouteBeanconnPerRoute=newConnPerRouteBean(MAX_ROUTE_CONNECTIONS);ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPerRoute); //设置连接超时时间HttpConnectionParams.setConnectionTimeout(httpParams,CONNECT_TIMEOUT); //设置读取超时时间HttpConnectionParams.setSoTimeout(httpParams,READ_TIMEOUT);

SchemeRegistryregistry=newSchemeRegistry();

registry.register(newScheme("http",PlainSocketFactory.getSocketFactory(),80)); registry.register(newScheme("https",SSLSocketFactory.getSocketFactory(),443));connectionManager=newThreadSafeClientConnManager(httpParams,registry);

}

publicstaticHttpClientgetHttpClient(){

returnnewDefaultHttpClient(connectionManager,httpParams);

}

}看到没

MAX_ROUTE_CONNECTIONS

正好是

400,跟CLOSE_WAIT 非常接近啊,难道是巧合?继续往下看。然后看看调用它的代码是什么样的: [java]viewplaincopyprint?publicstaticStringreadNet(StringurlPath){StringBuffersb=newStringBuffer();HttpClientclient=null;InputStreamin=null;InputStreamReaderisr=null;try{client=HttpConnectionManager.getHttpClient();HttpGetget=newHttpGet();get.setURI(newURI(urlPath));HttpResponseresponse=client.execute(get);if(response.getStatusLine().getStatusCode()!=200){ returnnull; }HttpEntityentity=response.getEntity();if(entity!=null){in=entity.getContent();.....}returnsb.toString();}catch(Exceptione){e.printStackTrace();returnnull;}finally{if(isr!=null){try{isr.close();}catch(IOExceptione){e.printStackTrace();}}if(in!=null){try{<spanstyle="color:#ff0000;">in.close();</span>}catch(IOExceptione){e.printStackTrace();}}}}很简单,就是个远程读取中文页面的方法。值得注意的是这一段代码是后来某某同学加上去的,看上去没啥问题,是用于非200状态的异常处理: [java]viewplaincopyprint?if(response.getStatusLine().getStatusCode()!=200){ returnnull; }代码本身没有问题,但是问题是放错了位置。如果这么写的话就没问题:[java]viewplaincopyprint?client=HttpConnectionManager.getHttpClient();HttpGetget=newHttpGet();get.setURI(newURI(urlPath));HttpResponseresponse=client.execute(get);HttpEntityentity=response.getEntity();if(entity!=null){ in=entity.getContent(); .......... }if(response.getStatusLine().getStatusCode()!=200){ returnnull; }returnsb.toString(); 看出毛病了吧。在这篇入门HttpClient4.X升级入门+http连接池使用)里头我提到了HttpClient4使用我们常用的InputStream.close()来确认连接关闭,前面那种写法 InputStreamin 根本就不会被赋值,意味着一旦出现非 200的连接,这个连接将永远僵死在连接池里头,太恐怖了。。。所以我们看到 CLOST_WAIT 数目为400,因为对一个路由的连接已经完全被僵死连接占满了。 。。其实上面那段代码还有一个没处理好的地方,异常处理不够严谨,所以最后我把代码改成了这样:[java]viewplaincopyprint?publicstaticStringreadNet(StringurlPath){StringBuffersb=newStringBuffer();HttpClientclient=null;InputStreamin=null;InputStreamReaderisr=null;HttpGetget=newHttpGet();try{clientHttpConnectionManager.getHttpClient();get.setURI(newURI(urlPath));HttpResponseresponse=client.execute(get);if(response.getStatusLine().getStatusCode()!=200){ get.abort(); returnnull; } HttpEntityentity=response.getEntity();if(entity!=null){ in=entity.getContent(); ......} returnsb.toString(); } catch(Exceptione) { get.abort();e.printStackTrace(); returnnull;finally { if(isr!=null){ try{ isr.close(); }

}catch(IOExceptione){e.printS

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论