对Apache HttpClient的优化,基于HttpClient4.4+的连接池(PoolingHttpClientConnectionManager),结合RestTemplate 使其在高QPS,并发请求下提高效率。

HttpClient优化点

  1. httpclient是一个线程安全的类,全局维护一个可避免httpclient反复创建带来的开销。
  2. 使用PoolingHttpClientConnectionManager连接池避免反复创建tcp连接
  3. 定时监控清理关闭服务端已CLOSE的连接
  4. 合理配置连接池的总连接数与并发数

HttpClient与RestTemplate实现

  1. 配置PoolingHttpClientConnectionManager连接池
public static CloseableHttpClient getCloseableHttpClient(boolean isRetry) {
	// 长连接保持30秒
	PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
	// 总连接数
	pollingConnectionManager.setMaxTotal(200);
	// 默认同路由的并发数
	pollingConnectionManager.setDefaultMaxPerRoute(100);
	HttpClientBuilder httpClientBuilder = HttpClients.custom();
	httpClientBuilder.setConnectionManager(pollingConnectionManager);
	// 重试次数,默认是3次,设置为2次,没有开启
	if (isRetry) {
	    httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
	} else {
	    httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
	}
	// 保持长连接配置,需要在头添加Keep-Alive
	httpClientBuilder.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE);
	
	CloseableHttpClient httpClient = httpClientBuilder.build();
	
	runIdleConnectionMonitor(pollingConnectionManager);
	return httpClient;
}	
  1. 自定义keepAliveStrategy
private static ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy(){
	return (response, context) -> {
	    HeaderElementIterator it = new BasicHeaderElementIterator
	            (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
	    while (it.hasNext()) {
	        HeaderElement he = it.nextElement();
	        String param = he.getName();
	        String value = he.getValue();
	        if (value != null && param.equalsIgnoreCase
	                ("timeout")) {
	            return Long.parseLong(value) * 1000;
	        }
	    }
	    return 60 * 1000;//如果没有约定,则默认定义时长为60s
	};
}
  1. 定时监控清理实现连接关闭
private static void runIdleConnectionMonitor(HttpClientConnectionManager clientConnectionManager) {
    FixedRateSchedule schedule = new FixedRateScheduleImpl();
    schedule.setPoolTag("IDLE_CONNECTION_MONITOR_POOL");
    schedule.init();
    schedule.schedule(() -> {
        //关闭过期的链接
        clientConnectionManager.closeExpiredConnections();
        //关闭闲置超过30s的链接
        clientConnectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
    }, IDLE_INITIALDELAY, IDLE_PERIOD, TimeUnit.MILLISECONDS);
}
  1. 代码

https://github.com/ChinaLHR/HttpClientOptimization

参考