ConnectionPoolTimeoutException:Timeout waiting for connection from pool

我做的是一个通过微信登录的商城,报错的地方就是登录的时候,起初在测试服务器上出现过一次ConnectionPoolTimeoutException:Timeout waiting for connection from pool

异常,不过当时因为忙着别的事情,而且重启服务器后就好了。再也没重现,之后发到生产服务器就开始大量的报此异常,登录这里全部阻塞住了。首先解决问题让用户可用,还是立马重启然后又好了,开始查询原因,异常如下:

2017-03-02 15:36:55  INFO WeChatServiceImpl:389 - 微信获取用户token,接口oauth2getAccessToken,start
2017-03-02 15:37:00  INFO WeChatServiceImpl:397 - 微信获取用户token
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:286)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
	at com.yunejian.yejTb.webUtil.http.WechatUserTokenRequestExecutor.execute(WechatUserTokenRequestExecutor.java:41)
	at com.yunejian.yejTb.webUtil.http.WechatUserTokenRequestExecutor.execute(WechatUserTokenRequestExecutor.java:22)
	at com.yunejian.yejTb.service.impl.WeChatServiceImpl.oauth2getAccessToken(WeChatServiceImpl.java:390)
	at com.yunejian.yejTb.service.impl.WeChatUserServiceImpl.getOpenId(WeChatUserServiceImpl.java:67)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:52)
	at org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:345)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:414)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:327)
	at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy161.getOpenId(Unknown Source)
	at com.yunejian.yejTb.controller.api.WeChatController.login(WeChatController.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)


首先分析异常,是在CloseableHttpClient执行请求时候抛出的,从连接池中获取链接的时间太长了,超时报错在PoolingHttpClientConnectionManager中,

    protected HttpClientConnection leaseConnection(Future<CPoolEntry> future, long timeout, TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
        try {
            CPoolEntry entry = (CPoolEntry)future.get(timeout, tunit);//此处报错
            if(entry != null && !future.isCancelled()) {
                Asserts.check(entry.getConnection() != null, "Pool entry with no connection");
                if(this.log.isDebugEnabled()) {
                    this.log.debug("Connection leased: " + this.format(entry) + this.formatStats((HttpRoute)entry.getRoute()));
                }

                return CPoolProxy.newProxy(entry);
            } else {
                throw new InterruptedException();
            }
        } catch (TimeoutException var7) {
            throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
        }
    }



分析代码问题出在用Future.get()来获取链接实体,当第一个请求超时的时候,剩下的调用Future.get()就全部获取连接超时,造成这种情况的原因是,在获取CloseableHttpClient对象的时候使用了单例模式。

    protected CloseableHttpClient getHttpclient() {
        if(null != httpClient){  //只有一个client引起的

            return httpClient;
        }
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setSocketTimeout(10000)
                .setConnectTimeout(10000)
                .setConnectionRequestTimeout(5000)
                .build();
        httpClient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
        return httpClient;

    }


但是还是有疑问,单例是产生了阻塞的问题,但是为什么报错的地方是Futrue.get呢,因为get方法中的timeOut是去的ConnectionRequestTimeOut,当时设置时候并没有在意这个参数,设置了5s,但是连接超时时已经有10s了。所以再到这就必然报错,为了验证 我把ConnectionRequestTimeOut设置为比ConnectionTimeout的时间短一些,果然报错就是connect timed out了,至此情况已经明了下一步解决问题。
最快也是最简单的解决办法就是取消单例模式,每次都创建一个对象,但是这么做会不会导致闲置的client太多呢,而且创建的成本本身也是很高的。所以我做了一次压测(之前就是因为没有做并发测试,不然早就发现这个问题了),模拟了100的并发量,发现没问题,通过JProfile发现堆中几乎没什么变化,因为在创建httpClient的具体显示中使用了一个connManager来管理连接,是从连接池中取的,所以没有问题。
总结下:首先项目没有进行压力测试这是问题没有及时发现并且重视的主要原因,其次在试用httpclient相关类尤其是参数设置的时候没仔细研究,都是想当然的使用,不可取,不可取。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值