了解Apache HTTP客户端中由PoolingHttpClientConnectionManager管理的连接的生命周期

问题描述

阅读了Apache HTTP组件模块的Connection Management文档后,我感到非常困惑,并且还有一些其他有关连接保持活动策略和连接逐出策略的资源。

其中使用了很多形容词来描述连接状态,例如staleidleavailableexpiredclosed等没有生命周期图来描述连接在这些状态之间如何变化。

我的困惑主要来自以下情况。

我设置了一个ConnectionKeepAliveStrategy,它通过下面的代码片段提供了5秒的KeepAliveDuration

        ConnectionKeepAliveStrategy keepAliveStrategy = ( httpResponse,httpContext ) -> {
            HeaderElementIterator iterator = 
                 new BasicHeaderElementIterator( httpResponse.headerIterator( HTTP.CONN_KEEP_ALIVE ) );
            while ( iterator.hasNext() )
            {
                HeaderElement header = iterator.nextElement();
                if ( header.getValue() != null && header.getName().equalsIgnoreCase( "timeout" ) )
                {
                    return Long.parseLong( header.getValue(),10) * 1000;
                }
            }
            return 5 * 1000;
        };
        this.client = HttpAsyncClients.custom()
                .setDefaultRequestConfig( requestConfig )
                .setMaxConnTotal( 500 )    
                .setMaxConnPerRoute( 500 )
                .setConnectionManager( this.cm )  
                .setKeepAliveStrategy( keepAliveStrategy )
                .build();

我正在与之交谈的服务器确实支持保持活动状态。在单批异步执行大约200个请求后,当我打印出连接管理器的池统计信息时,观察到以下信息。

Total Stats:
-----------------
Available: 139
Leased: 0
Max: 500
Pending: 0

然后等待30秒(到那时,已经超过了keep-alive超时时间了),我开始了一批新的相同的HTTP调用。检查连接管理器池统计信息后,可用连接数仍为139。

自从达到保持活动超时后,它是否应该为零? PoolStats Java doc指出Available是“空闲持久连接数”。空闲的持久连接是否被认为是活动的?

我认为Apache HttpClient: How to auto close connections by server's keep-alive time很受欢迎,但希望某些专家能对PoolingHttpClientConnectionManager管理的连接的生命周期给出深刻的解释。

其他一些常见问题:

  1. HttpAsyncClients.createdDefault()中使用的默认连接管理器是否自行处理连接保持活动策略和连接逐出?
  2. 哪些要求/限制可能要求自定义实现?他们会互相矛盾吗?

解决方法

记录我的一些进一步发现,这些发现可能部分可以作为答案。

  1. 无论是否使用ConnectionKeepAliveStrategy设置保持活动会话的超时,通过ESTABLISHED检查到的连接都将以netstat -apt的TCP状态结束。而且我观察到它们在我的Linux测试环境中大约5分钟后会自动回收。

  2. 如果不使用ConnectionKeepAliveStrategy,则在第二次请求批处理时,已建立的连接将被重用。

  3. 使用ConnectionKeepAliveStrategy并且尚未达到其超时时,在第二次请求批处理时,已建立的连接将被重用。

  4. 当使用ConnectionKeepAliveStrategy且超过其超时时,在第二批请求时,已建立的连接将被回收为TIME_WAIT状态,表明客户端已决定关闭连接。

  5. 可以通过在单独的连接退出线程中执行connectionManager.closeExpiredConnections();来积极地执行此回收,这将导致连接进入TIME_WAIT阶段。

我认为一般的观察是,连接池统计将ESTABLISHED个连接视为Available,并且连接超时策略保持超时的确会使连接失效,但是只需要花费在处理新请求时,或者在我们特别指示连接管理器关闭过期的连接时,就会生效。

来自Wikipedia的

TCP state diagram供参考。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...