HttpClient 4.3连接池参数配置及源码解读

    目前所在公司使用HttpClient 4.3.3版本发送Rest请求,调用接口。最近出现了调用查询接口服务慢的生产问题,在排查整个调用链可能存在的问题时(从客户端发起Http请求->ESB->服务端处理请求,查询数据并返回),发现原本的HttpClient连接池中的一些参数配置可能存在问题,如defaultMaxPerRoute、一些timeout时间的设置等,虽不能确定是由于此连接池导致接口查询慢,但确实存在可优化的地方,故花时间做一些研究。本文主要涉及HttpClient连接池、请求的参数配置,使用及源码解读。

 

    以下是本文的目录大纲:

    一、HttpClient连接池、请求参数含义

    二、执行原理及源码解读

        1、创建HttpClient,执行request

        2、连接池管理

            2.1、连接池结构

            2.2、分配连接 & 建立连接

            2.3、回收连接 & 保持连接

            2.4、instream.close()、response.close()、httpclient.close()的区别

            2.5、过期和空闲连接清理

    三、如何设置合理的参数

 

一、HttpClient连接池、请求参数含义

import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.nio.charset.CodingErrorAction;
import javax.net.ssl.SSLException;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.MessageConstraints;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

public class HttpClientParamTest {
	public static void main(String[] args) {
		/**
		 * 创建连接管理器,并设置相关参数
		 */
		//连接管理器,使用无惨构造
		PoolingHttpClientConnectionManager connManager 
		                            = new PoolingHttpClientConnectionManager();
		
		/**
		 * 连接数相关设置
		 */
		//最大连接数
		connManager.setMaxTotal(200); 
		//默认的每个路由的最大连接数
		connManager.setDefaultMaxPerRoute(100); 
		//设置到某个路由的最大连接数,会覆盖defaultMaxPerRoute
		connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 150); 
		
		/**
		 * socket配置(默认配置 和 某个host的配置)
		 */
		SocketConfig socketConfig = SocketConfig.custom()
				.setTcpNoDelay(true)     //是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
				.setSoReuseAddress(true) //是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
				.setSoTimeout(500)       //接收数据的等待超时时间,单位ms
				.setSoLinger(60)         //关闭Socket时,要么发送完所有数据,要么等待60s后,就关闭连接,此时socket.close()是阻塞的
	            .setSoKeepAlive(true)    //开启监视TCP连接是否有效
	            .build();
		connManager.setDefaultSocketConfig(socketConfig);
		connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig);
		
		/**
		 * HTTP connection相关配置(默认配置 和 某个host的配置)
		 * 一般不修改HTTP connection相关配置,故不设置
		 */
		//消息约束
		MessageConstraints messageConstraints = MessageConstraints.custom()
	            .setMaxHeaderCount(200)
	            .setMaxLineLength(2000)
	            .build();
		//Http connection相关配置
		ConnectionConfig connectionConfig = ConnectionConfig.custom()
	            .setMalformedInputAction(CodingErrorAction.IGNORE)
	            .setUnmappableInputAction(CodingErrorAction.IGNORE)
	            .setCharset(Consts.UTF_8)
	            .setMessageConstraints(messageConstraints)
	            .build();
		//一般不修改HTTP connection相关配置,故不设置
		//connManager.setDefaultConnectionConfig(connectionConfig);
        //connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT);
		
        /**
         * request请求相关配置
         */
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setConnectTimeout(2 * 1000)         //连接超时时间
                .setSocketTimeout(2 * 1000)          //读超时时间(等待数据超时时间)
                .setConnectionRequestTimeout(500)    //从池中获取连接超时时间
                .setStaleConnectionCheckEnabled(true)//检查是否为陈旧的连接,默认为true,类似testOnBorrow
                .build();
		
		/**
		 * 重试处理
		 * 默认是重试3次
		 */
		//禁用重试(参数:retryCount、requestSentRetryEnabled)
		HttpRequestRetryHandler requestRetryHandler = new DefaultHttpRequestRetryHandler(0, false);
		//自定义重试策略
		HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {

		    public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
		    	//Do not retry if over max retry count
		        if (executionCount >= 3) {
		            return false;
		        }
		        //Timeout
		        if (exception instanceof InterruptedIOException) {
		            return false;
		        }
		        //Unknown host
		        if (exception instanceof UnknownHostException) {
		            return false;
		        }
		        //Connection refused
		        if (exception instanceof ConnectTimeoutException) {
		            return false;
		        }
		        //SSL handshake exception
		        if (exception instanceof SSLException) {
		            return false;
		        }
		        
		        HttpClientContext clientContext = HttpClientContext.adapt(context);
		        HttpRequest request = clientContext.getRequest();
		        boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
		        //Retry if the request is considered idempotent
		        //如果请求类型不是HttpEntityEnclosingRequest,被认为是幂等的,那么就重试
		        //HttpEntityEnclosingRequest指的是有请求体的request,比HttpRequest多一个Entity属性
		        //而常用的GET请求是没有请求体的,POST、PUT都是有请求体的
		        //Res
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值