WebSphere Liberty部署应用后HTTPClient5.3.1出现CLOSE_WAIT问题咨询
问题:WebSphere Liberty共享JVM下HTTPClient 5连接池部署后出现CLOSE_WAIT连接
背景与实现
我们使用WebSphere Liberty Profile托管多个应用,所有应用运行在同一JVM下。部分应用采用HTTPClient 5.3.1调用API,连接池实现代码如下:
ConnectionConfig connConfig = ConnectionConfig.custom() .setConnectTimeout(connectTimeout, TimeUnit.MILLISECONDS) .setValidateAfterInactivity(validateAfterInactivity, TimeUnit.MILLISECONDS) .setSocketTimeout(socketTimeout, TimeUnit.MILLISECONDS) .setTimeToLive(TimeValue.ofSeconds(timeToLive)) .build(); //Building the custom Request config RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(connectionRequestTimeout, TimeUnit.MILLISECONDS) .setResponseTimeout(connectionRequestTimeout, TimeUnit.MILLISECONDS) .build(); connectionManager = PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() .setSslContext(SSLContexts.createSystemDefault()) .build()) .setDefaultSocketConfig(SocketConfig.custom() .setSoTimeout(socketTimeout, TimeUnit.MILLISECONDS) .build()) .setDefaultConnectionConfig(connConfig) .setMaxConnTotal(maxTotal) .setMaxConnPerRoute(defaultMaxPerRoute) .build(); //Building the http Client httpClient = HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionManagerShared(true) .setDefaultRequestConfig(requestConfig) .evictExpiredConnections() .setKeepAliveStrategy(keepAliveStrategy) .disableConnectionState() .evictIdleConnections(TimeValue.ofSeconds(evictIdleTime)) .build();
问题现象
连接池日常工作正常,可正常关闭socket,但在部署曾使用该连接池的应用时,系统会新建连接,而连接池中的部分socket会处于CLOSE_WAIT状态:
TCP <localhostip>:49260 <remoteserverip>:443 CLOSE_WAIT 17068 TCP <localhostip>:49362 <remoteserverip>:443 CLOSE_WAIT 17068 TCP <localhostip>:49363 <remoteserverip>:443 CLOSE_WAIT 17068 TCP <localhostip>:49364 <remoteserverip>:443 CLOSE_WAIT 17068 TCP <localhostip>:49365 <remoteserverip>:443 CLOSE_WAIT 17068 TCP <localhostip>:49366 <remoteserverip>:443 CLOSE_WAIT 17068
该问题仅在部署应用时出现,且因JVM为其他应用共享,无法重启进程。现咨询:
- 此是否为Apache HTTPClient5的Bug,有无修复方案?
- 在Windows服务器上能否从socket层面清除CLOSE_WAIT状态?
- 有无其他修复方案?无法使用JVM关闭事件。
解答
1. 是否为HTTPClient 5的Bug及修复方案
这大概率不是HTTPClient 5的原生Bug,而是共享连接池在应用热部署时的资源未正确释放导致的。
- 你设置了
setConnectionManagerShared(true),意味着连接池被多个应用共享,但WebSphere Liberty热部署时,旧应用的类加载器会被卸载,若旧应用持有连接池的引用未正确清理,连接池中的连接会因为引用残留,无法触发正常的关闭逻辑,导致远端主动关闭连接后,本地socket停留在CLOSE_WAIT状态。 - 修复方向:
- 避免在热部署场景下使用共享连接池,改为每个应用独立维护自己的连接池实例。
- 若必须共享,可监听WebSphere Liberty的应用生命周期事件(比如
javax.servlet.ServletContextListener的contextDestroyed方法),在应用卸载时主动调用connectionManager.closeExpiredConnections()和connectionManager.closeIdleConnections(TimeValue.ZERO),强制回收所有空闲连接。 - 升级HTTPClient 5到最新稳定版本(如5.4.x),检查官方是否有相关资源泄漏的修复补丁。
2. Windows服务器上能否从socket层面清除CLOSE_WAIT状态
从操作系统层面,无法直接强制清除CLOSE_WAIT状态的socket。CLOSE_WAIT状态表示远端已经关闭连接,本地应用尚未调用close()释放socket资源。只有当持有该socket的进程主动关闭它,或者进程终止,socket才会被系统回收。
- Windows上没有类似Linux
ss/tcpkill的工具可以直接强制关闭属于某个进程的特定socket,除非终止对应的进程,但你无法重启JVM,所以这个路径不可行。
3. 其他修复方案
除上述方案外,还有以下几种思路:
- 强化连接池自动回收策略:
- 缩短
validateAfterInactivity的时间,让连接池更频繁地检查连接有效性,发现已失效的CLOSE_WAIT连接时主动关闭。 - 进一步降低
evictIdleTime,设置更短的空闲连接驱逐周期,配合evictIdleConnections定时清理空闲连接。
- 缩短
- 添加连接有效性校验:在每次从连接池获取连接时,使用HTTPClient的
setConnectionValidator自定义校验逻辑,若发现连接处于失效状态(如CLOSE_WAIT),直接丢弃并重新创建连接。 - 启用应用类加载器隔离:调整WebSphere Liberty的配置,启用应用类加载器的严格隔离,确保旧应用的资源(包括连接池引用)在热部署时被完全清理,避免残留。
内容的提问来源于stack exchange,提问作者GKV
相关产品推荐
相关产品推荐

