Remote call using Http connection pool

Explain

http request is the most commonly used method of inter system interface call.

In java, there are many ways of http request. httpClient is a common way at present, and it is easy to use.

However, creating an httpClient is a time-consuming process. To improve performance, the http connection pool is usually used to get the httpClient object from the connection pool every time.

Introduction of jar package

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.6</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>fluent-hc</artifactId>
    <version>4.5.6</version>
</dependency>

Code example

1. Custom connection pool

public class HttpUtils {
    private final static Logger log = LoggerFactory.getLogger(HttpUtils.class);

    private static final int REQUEST_TIMEOUT = 12 * 1000; // Set request timeout 12 seconds
    private static final int TIMEOUT = 12 * 1000; // Connection timeout
    private static final int SO_TIMEOUT = 12 * 1000; // Data transmission timeout
    private static final String CHARSET = "UTF8";

    private static CloseableHttpClient httpClient = null;

    static {
        init();
    }
    public static void init() {
        try {
            // SSLContext
            SSLContextBuilder sslContextbuilder = new SSLContextBuilder();
            SSLContext sslContext = sslContextbuilder.loadTrustMaterial(null, (chain, authType) -> true).build();
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", new SSLConnectionSocketFactory(sslContext,
                            NoopHostnameVerifier.INSTANCE))
                    .build();

            // Create ConnectionManager
            PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            // Create socket configuration
            SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
            connManager.setDefaultSocketConfig(socketConfig);
            // Create message constraints
            MessageConstraints messageConstraints = MessageConstraints.custom().setMaxHeaderCount(200)
                    .setMaxLineLength(2000).build();
            // Create connection configuration
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setMalformedInputAction(CodingErrorAction.IGNORE)
                    .setUnmappableInputAction(CodingErrorAction.IGNORE).setCharset(Consts.UTF_8)
                    .setMessageConstraints(messageConstraints).build();
            connManager.setDefaultConnectionConfig(connectionConfig);
            connManager.setMaxTotal(200);
            connManager.setDefaultMaxPerRoute(20);
            // Create httpClient
            httpClient = HttpClients.custom().disableRedirectHandling().setConnectionManager(connManager).build();
        } catch (KeyManagementException e) {
            log.error("KeyManagementException", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException", e);
        } catch (Exception e) {
            log.error("Exception", e);
        }

    }

    public static String doGet(String url) throws Exception {
        return doGet(url, null);
    }

    /**
     * GET Method request data
     */
    public static String doGet(String url, Map<String, String> headerMap) throws Exception {
        HttpGet httpGet = new HttpGet(url);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SO_TIMEOUT).setConnectTimeout(TIMEOUT)
                .setConnectionRequestTimeout(REQUEST_TIMEOUT).build();
        httpGet.setConfig(requestConfig);
        if (headerMap != null) {
            for (String key : headerMap.keySet()) {
                httpGet.setHeader(key, headerMap.get(key));
            }
        }
        long responseLength = 0; // Response length
        String responseContent = null; // Response content
        String strRep = null;
        try {
            // Execute get request
            HttpResponse httpResponse = httpClient.execute(httpGet);

            // Get response message entity
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                responseLength = entity.getContentLength();
                // Cannot call this method repeatedly, IO stream is closed.
                responseContent = EntityUtils.toString(entity, CHARSET);
                // Get status code of HTTP response
                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.SC_OK) {
                    strRep = responseContent;
                }
                // Consume response content
                EntityUtils.consume(entity);
                // Do not need the rest
                httpGet.abort();
            }
        } finally {
            httpGet.releaseConnection();
        }

        return strRep;
    }
}

2. Do not use connection pool

public class HttpUtils2 {

    private final static Logger log = LoggerFactory.getLogger(HttpUtils2.class);
    private static final int REQUEST_TIMEOUT = 12 * 1000; // Set request timeout 12 seconds
    private static final int TIMEOUT = 12 * 1000; // Connection timeout
    private static final int SO_TIMEOUT = 12 * 1000; // Data transmission timeout
    private static final String CHARSET = "UTF8";

    /**
     * GET Method request data
     */
    public static String doGet(String url) {
        String strRep = null;
        HttpGet httpGet = new HttpGet(url);
        try {
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SO_TIMEOUT).setConnectTimeout(TIMEOUT)
                    .setConnectionRequestTimeout(REQUEST_TIMEOUT).build();
            httpGet.setConfig(requestConfig);
            HttpClient httpClient = HttpClients.createDefault();
            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity entity = httpResponse.getEntity();
            log.info("Response state: {}", httpResponse.getStatusLine());
            // Cannot call this method repeatedly, IO stream is closed.
            String responseContent = EntityUtils.toString(entity, CHARSET);
            // Get status code of HTTP response
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK) {
                strRep = responseContent;
            }
        } catch (Exception e) {
            log.error("get Request exception: {} get url: {}", e.getMessage(), url);
        } finally {
            httpGet.releaseConnection();
        }
        return strRep;
    }
}

3. Using fluent HC request

Fluent HC, a simple encapsulation of HttpClient, and its own connection pool, is more convenient to use

public class HttpUtils3 {

    private final static Logger log = LoggerFactory.getLogger(HttpUtils3.class);
    private static final int REQUEST_TIMEOUT = 12 * 1000; // Set request timeout 12 seconds
    private static final int SO_TIMEOUT = 12 * 1000; // Data transmission timeout
    private static final String CHARSET = "UTF8";

    /**
     * GET Method request data
     */
    public static String doGet(String url) {
        String strRep = null;
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpEntity entity = Request.Get(url)
                    .connectTimeout(REQUEST_TIMEOUT)
                    .socketTimeout(SO_TIMEOUT)
                    .execute().returnResponse().getEntity();
            // Cannot call this method repeatedly, IO stream is closed.
            strRep = EntityUtils.toString(entity, CHARSET);
        } catch (Exception e) {
            log.error("get Request exception: {} get url: {}", e.getMessage(), url);
        } finally {
            httpGet.releaseConnection();
        }

        return strRep;
    }
}

4. Use test comparison

Use three methods to call the interface 10 times in succession

public class HttpTest {
    public static void main(String[] args) throws Exception {
        Stopwatch stopWatch = Stopwatch.createStarted();
        for (int i = 0; i < 10; i++) {
            HttpUtils.doGet("http://www.baidu.com");
            long stime = stopWatch.elapsed(TimeUnit.MILLISECONDS);
            System.out.println("HttpUtils Time consuming:" + stime);
            stopWatch.reset().start();
        }
        System.out.println("------------------");
        for (int i = 0; i < 10; i++) {
            HttpUtils2.doGet("http://www.baidu.com");
            long stime = stopWatch.elapsed(TimeUnit.MILLISECONDS);
            System.out.println("HttpUtils2 Time consuming:" + stime);
            stopWatch.reset().start();
        }
        System.out.println("------------------");
        for (int i = 0; i < 10; i++) {
            HttpUtils3.doGet("http://www.baidu.com");
            long stime = stopWatch.elapsed(TimeUnit.MILLISECONDS);
            System.out.println("HttpUtils3 Time consuming:" + stime);
            stopWatch.reset().start();
        }
    }
}

The output results are as follows:

HttpUtils time: 4480
 HttpUtils time: 13
 HttpUtils time: 16
 HttpUtils time: 14
 HttpUtils time: 13
 HttpUtils time: 13
 HttpUtils time: 13
 HttpUtils time: 14
 HttpUtils time: 15
 HttpUtils time: 14
------------------
HttpUtils2 time consumption: 48
 HttpUtils2 time consumption: 25
 HttpUtils2 time consumption: 28
 HttpUtils2 time consumption: 25
 HttpUtils2 time consumption: 28
 HttpUtils2 time consumption: 33
 HttpUtils2 time consumption: 37
 HttpUtils2 time consumption: 30
 HttpUtils2 time consumption: 26
 HttpUtils2 time consumption: 32
------------------
HttpUtils3 time consumption: 47
 HttpUtils3 time consumption: 12
 HttpUtils3 time consumption: 13
 HttpUtils3 time consumption: 13
 HttpUtils3 time consumption: 12
 HttpUtils3 time consumption: 11
 HttpUtils3 time consumption: 13
 HttpUtils3 time consumption: 13
 HttpUtils3 time consumption: 13
 HttpUtils3 time consuming: 11

The first request takes a long time to initialize the object.

It can be seen from the results that the performance of custom connection pool is similar to that of fluent HC, and it takes a long time to directly initiate httpClient requests, which is 2-3 times the time of connection pool.

65 original articles published, 31 praised, 40000 visitors+
Private letter follow

Tags: Apache Java socket REST

Posted on Sun, 09 Feb 2020 23:51:53 -0500 by scross