• 一次HttpClient连接泄露排查


    一次HttpClient连接泄露排查

    在开发环境中,调试新功能时发现由于异常处理不严谨导致线程一直挂起的问题。

    故障

    在集成测试用,发现只要多次调用新开发的业务,就会出现前端卡死,后端响应线程一直挂起的情况,但没有任何报错

    查错

    每一次重现的时候最后一条log都是定位到有些历史的HttpClient的工具类上,接口封装上游是直接一个大块try-catch并且没有做任何的异常处理,调用的下游才是直接对Apache HttpClient的封装,眨眼看上去并没有什么问题。
    因为业务时异步并发调用接口,我在业务调用上改成timeout处理,断点发现有任务处于未完成状态,远程调用一直没有回调。然后我重新打开工具类,找到封装HttpClient调用的逻辑,搜索关于timeout的设置,如下:

    	RequestConfig
                    .custom()
    		.setSocketTimeout(socketTimeout)
    		.setConnectTimeout(connectTimeout)
    		.build();
    

    然后看了一下文档,发现还有一个timeout的参数ConnectionRequestTimeout,然后我改动一下代码:

    	RequestConfig
                     .custom()
    		 .setSocketTimeout(socketTimeout)
    	         .setConnectTimeout(connectTimeout)
    		 .setConnectionRequestTimeout(requestTimeOut)
    		 .build();
    

    再次编译运行,问题依旧,但有了新发现,有新的异常捕获日志:

    org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection
    

    然后定位到调用下游逻辑块:

    	HttpResponse resp = client.execute(httpPost);	//这里!
    	if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    		HttpEntity httpEntity = resp.getEntity();
    		respContent = EntityUtils.toString(httpEntity, "UTF-8");
    	}
    

    这段代码中抛出了异常,给上游的调用捕获了,但是上下文中httpPost并没有做连接释放的处理,所以连接池中的连接越来越少。

    解决

    在逻辑中加上try-finally,显式调用释放请求连接。

    	try {
    		HttpResponse resp = client.execute(httpPost);
    		if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    			HttpEntity httpEntity = resp.getEntity();
    			respContent = EntityUtils.toString(httpEntity, "UTF-8");
    			EntityUtils.consume(httpEntity);
    		}
    	} finally {
    		httpPost.releaseConnection();
    	}
    
  • 相关阅读:
    Java Switch
    老徐杂谈:年后的第一个双休,你在做什么?
    测试必备技能系列4:如何用SSH向linux服务器上传下载文件
    Git从零教你入门(4):Git服务之 gogs部署安装
    你知道哪些linux命令,能把文件上传到远程linux服务器
    一个7年以上测试工程师的2016思考
    老徐谈谈软件测试职业的现状,以及市场情况
    mac 远程连接服务器
    Git从零开始怎么学?
    分享 | Git常用的一些命令
  • 原文地址:https://www.cnblogs.com/jason-koo/p/12905362.html
Copyright © 2020-2023  润新知