一次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();
	}
原文地址:https://www.cnblogs.com/jason-koo/p/12905362.html