HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查...
今天解决了一个HttpClient的异常,汗啊,一个HttpClient使用稍有不慎都会是毁灭级别的啊。
这里有之前因为route配置不当导致服务器异常的一个处理:http://blog.csdn.net/shootyou/article/details/6415248
里面的HttpConnectionManager实现就是我在这里使用的实现。
问题表现:
tomcat后台日志发现大量异常
- org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection
时间一长tomcat就无法继续处理其他请求,从假死变成真死了。
linux运行:
- netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, 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实现:
- public class HttpConnectionManager {
- private static HttpParams httpParams;
- private static ClientConnectionManager connectionManager;
- /**
- * 最大连接数
- */
- public final static int MAX_TOTAL_CONNECTIONS = 800;
- /**
- * 获取连接的最大等待时间
- */
- public final static int WAIT_TIMEOUT = 60000;
- /**
- * 每个路由最大连接数
- */
- public final static int MAX_ROUTE_CONNECTIONS = 400;
- /**
- * 连接超时时间
- */
- public final static int CONNECT_TIMEOUT = 10000;
- /**
- * 读取超时时间
- */
- public final static int READ_TIMEOUT = 10000;
- static {
- httpParams = new BasicHttpParams();
- // 设置最大连接数
- ConnManagerParams.setMaxTotalConnections(httpParams, MAX_TOTAL_CONNECTIONS);
- // 设置获取连接的最大等待时间
- ConnManagerParams.setTimeout(httpParams, WAIT_TIMEOUT);
- // 设置每个路由最大连接数
- ConnPerRouteBean connPerRoute = new ConnPerRouteBean(MAX_ROUTE_CONNECTIONS);
- ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPerRoute);
- // 设置连接超时时间
- HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);
- // 设置读取超时时间
- HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT);
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
- connectionManager = new ThreadSafeClientConnManager(httpParams, registry);
- }
- public static HttpClient getHttpClient() {
- return new DefaultHttpClient(connectionManager, httpParams);
- }
- }
看到没MAX_ROUTE_CONNECTIONS 正好是400,跟CLOSE_WAIT非常接近啊,难道是巧合?继续往下看。
然后看看调用它的代码是什么样的:
- public static String readNet (String urlPath)
- {
- StringBuffer sb = new StringBuffer ();
- HttpClient client = null;
- InputStream in = null;
- InputStreamReader isr = null;
- try
- {
- client = HttpConnectionManager.getHttpClient();
- HttpGet get = new HttpGet();
- get.setURI(new URI(urlPath));
- HttpResponse response = client.execute(get);
- if (response.getStatusLine ().getStatusCode () != 200) {
- return null;
- }
- HttpEntity entity =response.getEntity();
- if( entity != null ){
- in = entity.getContent();
- .....
- }
- return sb.toString ();
- }
- catch (Exception e)
- {
- e.printStackTrace ();
- return null;
- }
- finally
- {
- if (isr != null){
- try
- {
- isr.close ();
- }
- catch (IOException e)
- {
- e.printStackTrace ();
- }
- }
- if (in != null){
- try
- {
- <span style="color:#ff0000;">in.close ();</span>
- }
- catch (IOException e)
- {
- e.printStackTrace ();
- }
- }
- }
- }
很简单,就是个远程读取中文页面的方法。值得注意的是这一段代码是后来某某同学加上去的,看上去没啥问题,是用于非200状态的异常处理:
- if (response.getStatusLine ().getStatusCode () != 200) {
- return null;
- }
代码本身没有问题,但是问题是放错了位置。如果这么写的话就没问题:
- client = HttpConnectionManager.getHttpClient();
- HttpGet get = new HttpGet();
- get.setURI(new URI(urlPath));
- HttpResponse response = client.execute(get);
- HttpEntity entity =response.getEntity();
- if( entity != null ){
- in = entity.getContent();
- ..........
- }
- if (response.getStatusLine ().getStatusCode () != 200) {
- return null;
- }
- return sb.toString ();
看出毛病了吧。在这篇入门(HttpClient4.X 升级 入门 + http连接池使用) 里头我提到了HttpClient4使用我们常用的InputStream.close()来确认连接关闭,前面那种写法InputStream in 根本就不会被赋值,意味着一旦出现非200的连接,这个连接将永远僵死在连接池里头,太恐怖了。。。所以我们看到CLOST_WAIT数目为400,因为 对一个路由的连接已经完全被僵死连接占满了。。。
其实上面那段代码还有一个没处理好的地方,异常处理不够严谨,所以最后我把代码改成了这样:
- public static String readNet (String urlPath)
- {
- StringBuffer sb = new StringBuffer ();
- HttpClient client = null;
- InputStream in = null;
- InputStreamReader isr = null;
- HttpGet get = new HttpGet();
- try
- {
- client = HttpConnectionManager.getHttpClient();
- get.setURI(new URI(urlPath));
- HttpResponse response = client.execute(get);
- if (response.getStatusLine ().getStatusCode () != 200) {
- get.abort();
- return null;
- }
- HttpEntity entity =response.getEntity();
- if( entity != null ){
- in = entity.getContent();
- ......
- }
- return sb.toString ();
- }
- catch (Exception e)
- {
- get.abort();
- e.printStackTrace ();
- return null;
- }
- finally
- {
- if (isr != null){
- try
- {
- isr.close ();
- }
- catch (IOException e)
- {
- e.printStackTrace ();
- }
- }
- if (in != null){
- try
- {
- in.close ();
- }
- catch (IOException e)
- {
- e.printStackTrace ();
- }
- }
- }
- }
显示调用HttpGet的abort,这样就会直接中止这次连接,我们在遇到异常的时候应该显示调用,因为谁能保证异常是在InputStream in赋值之后才抛出的呢。
好了 ,分析完毕,明天准备总结下CLOSE_WAIT和TIME_WAIT的区别。
HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查...相关推荐
- HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查
HttpClient连接池抛出大量ConnectionPoolTimeoutException: Timeout waiting for connection异常排查 参考文章: (1)HttpCli ...
- 关于druid数据连接池抛出的 connection holder is null 异常
大概跑了三十分钟~~~这配置~~~这程序~~~ 然后华丽丽的报异常了~~~ 具体异常是这样的, ? 1 2 3 4 5 6 7 8 9 10 11 12 13 DEBUG: (BaseJdbcLogg ...
- Http持久连接与HttpClient连接池
以下文章来源方志朋的博客,回复"666"获面试宝典 一.背景 HTTP协议是无状态的协议,即每一次请求都是互相独立的.因此它的最初实现是,每一个http请求都会打开一个tcp so ...
- Http 持久连接与 HttpClient 连接池
转载自 Http 持久连接与 HttpClient 连接池 一.背景 HTTP协议是无状态的协议,即每一次请求都是互相独立的.因此它的最初实现是,每一个http请求都会打开一个tcp socket连 ...
- Axis2调用webservice报错 AxisFault: Timeout waiting for connection
记录一次正式环境服务报错排查记录. 某日被通知线上服务告警,错误日志全是 Timeout waiting for connection 首先梳理项目架构,项目很简单,就是一个使用axis2构建的web ...
- 大并发下Timeout waiting for connection from pool 解决方案
当前项目采用SpringCloud分布式架构 , 服务间采用REST接口请求 . 最近频发连接获取超时(本质上是HttpClient的连接超时)的问题 , 如下图 : 这是因为HttpClient在并 ...
- 【java】大并发下Timeout waiting for connection from pool 解决方案
1.概述 今天我也遇到这个情况了. 转载:大并发下Timeout waiting for connection from pool 解决方案 但是我是FLink下遇到的,在processfuntion ...
- 问题备忘: httpclient连接池异常引发的惨案
1. 问题描述 客户端A --> Ngnix --> 服务B Ngnix做服务B的负载,客户端访问服务B时,客户端偶尔会有抛出TimeoutException异常. 举个例子:如A在09: ...
- HttpClient连接池泄露
现象 内部提供了一个文件上传的SDK,通过Apache HttpClient访问公司内部的文件服务器进行文件上传,然后偶尔会有同事反馈文件没有上传成功,但是文件服务器这边查看log也并没有收到请求, ...
最新文章
- 53个Python库,你必须要试试
- 版本管理工具 (git 或者 svn)
- dotNetCore操作Redis(含CentOS7哨兵模式部署)
- publiccms中,怎么修改默认的端口8080以及默认上下文名称
- JAX-RS 2.0的新功能– @BeanParam批注
- mysql union 与 union all 语法及用法
- linux查找指定修改时间的文件夹,linux 查找某个日期以后修改过哪些文件 shell脚本...
- Flutter开发系列教程
- 18-CSS问题-让多个div横排显示并设置间距解决方案
- creo工程图模板_Creo工程图的优越性总结(仅供参考),来自网友与君共享
- Sharepoint 浅谈 [转]
- 例2.7 输出梯形 - 九度教程第14题(排版题)
- JAVA算法:M个苹果放到N个盘子中的方法(JAVA代码)
- 华为手机字体改简体_华为繁体字体怎么更换 华为手机字体改简体
- Robotics: Computational Motion Planning(路径规划)笔记(完):人工势场法(Artificial Potential Fields)
- 微软小娜关闭服务器,图文详解彻底关闭windows10系统里的小娜(Cortana)语音服务-系统操作与应用
-亦是美网络...
- 2017年的知识清单
- 最小二乘法求线性回归方程
- 基于java客户关系管理系统
- 采用Windows PowerShell运行conda activate xx出现 C:\Users\xxx\Documents\WindowsPowerShell\profile.ps1报错问题
热门文章
- bfgs算法matlab程序,BFGS优化算法及应用实例.docx
- java自己实现读写锁_关于读写锁算法的Java实现及思考
- ckplayer php,ckplayer 网页视频播放插件
- 塔利亚菲科 ajax,[欧冠小组赛第4轮]阿贾克斯 3-1 中日德兰
- 智能车竞赛技术报告 | 节能信标组 - 宿迁学院 - MAkkaPakka
- 智能车竞赛技术报告 | 单车拉力组 - 长春理工大学- 追风零队 2021
- 2021年春季学期-信号与系统-第十五次作业参考答案-第三小题参考答案
- 用于计算无线充电中LCC补偿网络器件参数的小程序
- 2021年春季学期-信号与系统-第四次作业参考答案-MATLAB实验1
- HX711双通道AD转换模块