httpclient版本
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5</version>
        </dependency>
连接管理

1. 默认使用连接池的连接管理器

httpclient默认使用的PoolingHttpClientConnectionManager这个类作为连接管理器,当然还提供了另外一个连接管理的类:BasicHttpClientConnectionManager。

PoolingHttpClientConnectionManager与BasicHttpClientConnectionManager的区别是,前者池化连接,也就是说,缓存一些长连接,在并发过高的情况下连接池的性能可是很明显的,毕竟高并发的时候,连接建立的过程也是比较耗时的,使用连接池,如果服务器响应很快的情况下,TPS可以有一个倍数的提升。后者是只缓存一个连接,如果下次请求与缓存的连接的路由信息不一致,则关闭缓存连接,重新建立一条新连接。

以前没怎么用过httpclient,刚开始使用的时候,我本来以为httpclient默认并未使用连接池,后来,我使用100个线程压测服务器的某个接口的时候,查看TCP连接信息,发现在一直都是只有2个连接建立状态,我使用的服务器,设置了100个工作线程,正常情况下应该是会出现成百上千甚至上万个TCP连接信息,有100个连接建立的状态,然后debug源码查找原因的时候,才发现它默认使用的就是连接池管理器,非常nice。

建议:使用连接池就行,一般不用更换为BasicHttpClientConnectionManager,但是需要对这个连接池管理器的相关配置做下调整,看下文。

2. 连接池配置

有几个默认配置如下:

最大连接数:20

每个路由最大连接数:2

获取连接的等待时间:-1(一直等下去,直到拿到可用连接)

最大连接数指的是一个客户端可以与服务器建立的最大连接数,每个路由最大连接数是指1个主机进程允许建立的最大连接数,一个路由信息的标志大概这个样子:http://127.0.0.1:8080。获取连接的等待时间是当请求过来时,已经没有可用连接,需要等待正在使用的连接释放之后,才有可用连接获取到的等待时间,默认是无限等下去,可以设置一个时间,单位毫秒。当前超过这个时间的时候,抛出异常直接返回。

p.s. 关于连接管理这部分有兴趣可以看下源码,实现并不复杂。

连接数默认的配置值还是比较小的,在实际场景中应当根据需要设置的大点。如下示例:

    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(2000);// 最大连接数
        connectionManager.setDefaultMaxPerRoute(100);//默认连接数

p.s. 也可以设置不同路由的最大连接数设置不同的值,并不一定是全局统一的值。

3. 获取连接的等待时间设置生效问题

我本来是这样设置的:

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // ... 连接池管理器自定义配置
        RequestConfig requestConfig = RequestConfig
                .custom()
                //...其它配置
                .setConnectionRequestTimeout(1000)
                .build();
        CloseableHttpClient httpClient = HttpClients
                .custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

因为我看到RequestConfig类提供的有设置获取连接的等待时间的接口,测试的时候,发现不生效,后来debug源码的时候,才发现根本不会读取这个配置。

想要这个配置生效,可以在构建HttpRequestBase或者它的子类如HttpGet时,设置RequestConfig,它下面的实现是从这里获取连接等待超时的值设置(我也是dubug的几遍源码,没有找到其它突破口,最终从源码中推测出这种设置,如有其它好的方案,欢迎告知),如下示例:

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // ... 连接池管理器自定义配置
        RequestConfig requestConfig = RequestConfig
                .custom()
                //...其它配置
                .setConnectionRequestTimeout(1000)
                .build();
        CloseableHttpClient httpClient = HttpClients
                .custom()
                .setConnectionManager(connectionManager)
                /*.setDefaultRequestConfig(requestConfig)*/
                .build();
        HttpGet httpGet = new HttpGet();
        httpGet.setConfig(requestConfig);
        httpClient.execute(httpGet);

p.s. 我上面的代码都是个示例,并不能直接来用,能说明意思就行,真正的实现还是稍为复杂点的,包括https协议的处理以及一些其它相关配置。