HttpClient报错Timeout waiting for connection from pool
报错现象
线上项目使用HttpClient请求第三方的HTTP资源,并发量高的时候,日志框报Timeout waiting for connection from pool
客户端的现象是有时正常,有时报错
原因分析
网上查找资料,很多照搬某个博客的解决方法,大致是合理的使用EntityUtils.consume及时释放请求连接
这个说法没错,但是这里的问题不是请求连接释放不当导致的
出现这个异常是因为新的请求来的时候,需要到HttpClient的线程池里面获取一个连接,作为请求连接
当请求等待获取连接的时间超过设置的connectionRequestTimeout,就会抛出Timeout waiting for connection from pool异常
解决方法
- 合理的配置HttpClient的连接池大小
clientBuilder.setMaxConnTotal(maxConnections);
2. 结合业务现状配置连接超时时间
RequestConfig.custom().
setConnectTimeout(connectTimeout).
setSocketTimeout(readTimeout).
.setConnectionRequestTimeout(connectionRequestTimeout).build();
HttpClientUtil.java
public class HttpClientUtil {
protected static Log logger = LogFactory.getLog(HttpClientUtil.class);
// 连接管理器
private static PoolingHttpClientConnectionManager cm;
private static String EMPTY_STR = "";
private static String UTF_8 = "UTF-8";
// 请求配置
private static RequestConfig requestConfig;
private static void init() {
if (cm == null) {
cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(1500);// 整个连接池最大连接数
cm.setDefaultMaxPerRoute(1500);// 每路由最大连接数,默认值是2
// 从连接池获取连接的timeout
int connectionRequestTimeout = 20000;
// 客户端从服务器读取数据的timeout
int socketTimeout = 10000;
// 客户端和服务器建立连接的timeout
int connectTimeout = 10000;
// 设置请求超时时间
requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(connectionRequestTimeout)
.setSocketTimeout(socketTimeout)
.setConnectTimeout(connectTimeout).build();
}
}
/**
* 通过连接池获取HttpClient
*
* @return
*/
public static CloseableHttpClient getHttpClient() {
init();
return HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setConnectionManagerShared(true).build();
}
try {
HttpEntity entity =null;
CloseableHttpResponse response =null;
HttpPost httpPost = new HttpPost(xmlPath);
CloseableHttpClient httpClient = HttpClientUtil.getHttpClient();
BufferedReader reader =null;
InputStream inputStream = null;
try {
response = httpClient.execute(httpPost); // 执行请求
logger.info("StatusCode="+response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_OK) {
logger.info(zXFileUrl+"?downloadPath="+downloadPath+"&yyid="+yyid+"&xzrsfzh="+xzrsfzh+"&xzrxm="+xzrxm+"&xzrjg="+xzrjg);
logger.info("Post请求失败,响应状态码 :" + response.getStatusLine().getStatusCode() );
result.put("code", 1);
result.put("msg", "无法获取网络文件");
}
if(response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK){
entity = response.getEntity();
System.out.println(entity.getContent());
DocumentBuilder builder = builderFactory.newDocumentBuilder();
inputStream=entity.getContent();
reader = new BufferedReader(new InputStreamReader(inputStream, "gbk"));
InputSource is = new InputSource(reader);
document = builder.parse(is);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
logger.info(zXFileUrl+"?downloadPath="+downloadPath+"&yyid="+yyid+"&xzrsfzh="+xzrsfzh+"&xzrxm="+xzrxm+"&xzrjg="+xzrjg);
logger.info("[maperror] HttpClientUtil ClientProtocolException : " + e.getMessage());
result.put("code", 1);
result.put("msg", "error");
} catch (IOException e) {
e.printStackTrace();
logger.info(zXFileUrl+"?downloadPath="+downloadPath+"&yyid="+yyid+"&xzrsfzh="+xzrsfzh+"&xzrxm="+xzrxm+"&xzrjg="+xzrjg);
logger.info("[maperror] HttpClientUtil IOException : " + e.getMessage());
result.put("code", 1);
result.put("msg", "error");
} finally {
if(inputStream != null){
try {
inputStream.close();
}catch (Exception e){
e.printStackTrace();
result.put("code", 1);
result.put("msg","error");
}
}
if(reader != null){
try {
reader.close();
}catch (Exception e){
e.printStackTrace();
result.put("code", 1);
result.put("msg","error");
}
}
if (entity != null) {
try {
EntityUtils.consumeQuietly(entity); // 关闭response
} catch (Exception e) {
e.printStackTrace();
result.put("code", 1);
result.put("msg","error");
}
}
httpPost.releaseConnection();
if(response != null){
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
result.put("code", 1);
result.put("msg","error");
}
}
}
} catch (Exception e) {
e.printStackTrace();
logger.info(zXFileUrl+"?downloadPath="+downloadPath+"&yyid="+yyid+"&xzrsfzh="+xzrsfzh+"&xzrxm="+xzrxm+"&xzrjg="+xzrjg);
logger.info(">>>>> file content is error xml:" + downloadPath + "--" + e.getMessage());
result.put("code", 1);
result.put("msg","error");
}