httpclient-Connection pool shut down 问题排查

  • Post author:
  • Post category:其他



提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档




问题描述

一次线上环境,基于netty实现tpc server,大量接受客户端请求,运行几天后出现进程僵死现象,通过jstack工具排查线程栈信息,并未发现线程异常的情况;最终再大量的日志中出现

java.lang.IllegalStateException: Connection pool shut down
        at org.apache.http.util.Asserts.check(Asserts.java:34) ~[httpcore-4.4.10.jar!/:4.4.10]
        at org.apache.http.pool.AbstractConnPool.lease(AbstractConnPool.java:191) ~[httpcore-4.4.10.jar!/:4.4.10]
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.requestConnection(PoolingHttpClientConnectionManager.java:267) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:176) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) ~[httpclient-4.5.6.jar!/:4.5.6]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) ~[httpclient-4.5.6.jar!/:4.5.6]
        at com.tsn.common.utils.utils.tools.http.AbstractHttpRequest.excuteReturnObj(AbstractHttpRequest.java:82) ~[tsn-common-utils-1.0.0-SNAPSHOT.jar!/:1.0.0-SNAPSHOT]



httpclient连接池分析

public class HttpClientUtils {
	private static PoolingHttpClientConnectionManager poolClientConnManager;	
	public static PoolingHttpClientConnectionManager getPoolClientConnManager() {
		return poolClientConnManager;
	}
	......
}
TotalStats totalStats =  poolClientConnManager.getTotalStats()
leased 表示当前正在被使用的连接。正常情况下不会长时间持续增长,如果出现说明连接未释放
pending 表示多少个请求数正在等待连接池空闲连接。
max 表示路由最大可以创建的连接数
available 表示连接池中空闲等待的连接数

初步分析在tcp server中接受大量请求后会同时请求外部接口数据(业务需要),请求客户端使用httpclient,采用的连接池,因此觉得对其进行优化



一、使用步骤



1.调整httpclient并发参数

  • 原配置
httpclient.poolMaxTotal=10
httpclient.maxPerRoute=5
  • 修改,根据实际情况进行调整
httpclient.poolMaxTotal=500
httpclient.maxPerRoute=250

1.poolMaxTotal 表示总共tcp最大连接数

2.maxPerRoute 表示每个路由最大连接数

3.maxTotal和maxPerRoute请求过大,设置过小,同时客户端调用超时的情况下会导致连接池中没有闲置连接,会使netty异步线程池中的队列数据堆叠的越来越大,最终导致内存oom

4.这里的场景调用的路由为2个,每个分配最大25个连接数,总共设置50,根据实际情况调整即可。

poolMaxTotal 和 maxPerRoute 记得同时设置



2.减少httpclient的连接超时,请求超时时间

RequestConfig.custom().setSocketTimeout(2*1000).setConnectTimeout(2*1000);

同时设置2s,根据实际情况调整,避免延迟时间过长处理缓慢



3.关闭定时清理

httpclient = HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true).build();

setConnectionManagerShared(true) 关闭定时清理长时间的闲置的连接,在大量频繁请求,使用线程池的情况下,进行关闭,充分利用连接,为false表示开启,true表示不开启

if (!(this.connManagerShared)) {
			if (closeablesCopy == null) {
				closeablesCopy = new ArrayList(1);
			}
			HttpClientConnectionManager cm = connManagerCopy;

			if ((this.evictExpiredConnections) || (this.evictIdleConnections)) {
				IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(
						cm, (this.maxIdleTime > 0L) ? this.maxIdleTime : 10L,
						(this.maxIdleTimeUnit != null) ? this.maxIdleTimeUnit
								: TimeUnit.SECONDS, this.maxIdleTime,
						this.maxIdleTimeUnit);

				closeablesCopy.add(new Closeable(connectionEvictor) {
					public void close() throws IOException {
						this.val$connectionEvictor.shutdown();
						try {
							this.val$connectionEvictor.awaitTermination(1L,
									TimeUnit.SECONDS);
						} catch (InterruptedException interrupted) {
							Thread.currentThread().interrupt();
						}
					}
				});
				connectionEvictor.start();
			}
			closeablesCopy.add(new Closeable(cm) {
				public void close() throws IOException {
					this.val$cm.shutdown();
				}

			});
		}



版权声明:本文为weixin_38548413原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。