zoukankan      html  css  js  c++  java
  • HttpClient客户端网络编程——高可用、高并发

      本文是HttpClient的学习博客,RestTemplate是基于HttpClient的封装,feign可基于HttpClient进行网络通信。

      那么作为较底层的客户端网络编程框架,该怎么配置使其能高可用,高并发,可支持Https协议呢?通读本文也许你会有答案或者启发。

      本文是Maven项目,基于Spring,在本Demo中使用了更方便的SpringBoot。

      以后随着理解HttpClient更深入的时候会不定期更新本博客,也欢迎感兴趣的博友交流和讨论。

    一、本文目录

      1. 代码实现

      2. 测试验证

      3. 后记

    二、代码实现

    1. 项目依赖

     1 <dependency>
     2             <groupId>org.springframework.boot</groupId>
     3             <artifactId>spring-boot-starter</artifactId>
     4         </dependency>
     5 
     6         <!--httpclient-->
     7         <dependency>
     8             <groupId>org.apache.httpcomponents</groupId>
     9             <artifactId>httpclient</artifactId>
    10             <version>4.5.12</version>
    11         </dependency>
    12 
    13         <!--alibaba JSON-->
    14         <dependency>
    15             <groupId>com.alibaba</groupId>
    16             <artifactId>fastjson</artifactId>
    17             <version>1.2.70</version>
    18         </dependency>
    19 
    20         <dependency>
    21             <groupId>org.springframework.boot</groupId>
    22             <artifactId>spring-boot-starter-test</artifactId>
    23             <scope>test</scope>
    24         </dependency>
    pom.xml

    2. 项目结构

      

    3. 项目配置

     1 #HttpClient配置
     2 httpClient:
     3   #重试次数
     4   retryCount: 3
     5   #重启开关
     6   requestSentRetryEnabled: true
     7   #HttpClient连接池配置
     8   pool:
     9     #总连接数
    10     maxTotal: 200
    11     #每个路由默认连接数,某一个/每服务每次能并行接收的请求数量
    12     defaultMaxPerRoute: 50
    13     #Validate connections after 15 sec of inactivity  15000
    14     validateAfterInactivity: 1000
    15     #idle超时时间
    16     idleTimeOut: 3
    17     socketCfg:
    18       #是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
    19       tcpNoDelay: true
    20       #是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
    21       soReuseAddress: true
    22       #接受数据的等待超时时间,单位ms
    23       soTimeOut: 500
    24       #关闭Socket时,要么发送完所有数据,要么等待60s后,就关闭连接,此时socket.close()是阻塞的
    25       soLinger: 60
    26       #开启监视TCP连接是否有效
    27       soKeepAlive: true
    application.yml

    4. HttpClient客户端配置类

      通过配置连接池管理对象PoolingHttpClientConnectionManager,设置两个重要参数maxTotal和defaultMaxPerRoute,和其它参数。本文参数配置参考官方文档httpcomponents-client-4.5.x,文档上面的参数更多更齐全,包括HttpConnectionFactory、DnsResolver、ConnectionConfig、RequestConfig、RequestConfig、HttpClientContext、设置代理。这些参数本文没有配置,使用HttpClient的默认配置,感兴趣想继续深入研究的可以去学习了解。BackoffManager可以在连接池处于闲暇时进行收缩,不过网络上资料较少,目前还没研究出怎么使用和配置。

      1 package com.example.httpclientdemo.common.config.http.client;
      2 
      3 import org.apache.http.config.Registry;
      4 import org.apache.http.config.RegistryBuilder;
      5 import org.apache.http.config.SocketConfig;
      6 import org.apache.http.conn.socket.ConnectionSocketFactory;
      7 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
      8 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
      9 import org.apache.http.impl.client.*;
     10 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
     11 import org.apache.http.ssl.SSLContexts;
     12 import org.springframework.beans.factory.annotation.Value;
     13 import org.springframework.context.annotation.Bean;
     14 import org.springframework.context.annotation.Configuration;
     15 
     16 import java.util.concurrent.TimeUnit;
     17 
     18 /**
     19  * HttpClient客户端配置类
     20  *
     21  * @author 复姓江山
     22  * @date 2021/02/08
     23  */
     24 @Configuration
     25 public class HttpClientConfig {
     26 
     27     /**
     28      * closeableHttpClient连接对象,支持HTTPS使用SSL套接层
     29      *
     30      * @param httpClientPoolManager   HttpClient连接池管理对象
     31      * @param retryCount              重试次数
     32      * @param requestSentRetryEnabled 重启开关
     33      * @return closeableHttpClient连接对象
     34      */
     35     @Bean
     36     public CloseableHttpClient closeableHttpClient(final PoolingHttpClientConnectionManager httpClientPoolManager,
     37                                                    @Value("${httpClient.retryCount}") final int retryCount,
     38                                                    @Value("${httpClient.requestSentRetryEnabled}") final
     39                                                    boolean requestSentRetryEnabled) {
     40 
     41         return HttpClients.custom()
     42                 .setDefaultCookieStore(new BasicCookieStore())
     43                 .setDefaultCredentialsProvider(new BasicCredentialsProvider())
     44                 .setConnectionManager(httpClientPoolManager)
     45                 .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, requestSentRetryEnabled))
     46                 .build();
     47     }
     48 
     49     /**
     50      * 默认socket configuration
     51      *
     52      * @param tcpNoDelay     是否立即发送数据,设置为true会关闭Socket缓冲,默认为false
     53      * @param soReuseAddress 是否可以在一个进程关闭Socket后,即使它还没有释放端口,其它进程还可以立即重用端口
     54      * @param soTimeOut      接受数据的等待超时时间,单位ms
     55      * @param soLinger       关闭Socket时,要么发送完所有数据,要么等待60s后,就关闭连接,此时socket.close()是阻塞的
     56      * @param soKeepAlive    开启监视TCP连接是否有效
     57      * @return 默认socket configuration
     58      */
     59     @Bean
     60     public SocketConfig defaultSocketConfig(@Value("${httpClient.pool.socketCfg.tcpNoDelay}") final boolean tcpNoDelay,
     61                                             @Value("${httpClient.pool.socketCfg.soReuseAddress}") final boolean soReuseAddress,
     62                                             @Value("${httpClient.pool.socketCfg.soTimeOut}") final int soTimeOut,
     63                                             @Value("${httpClient.pool.socketCfg.soLinger}") final int soLinger,
     64                                             @Value("${httpClient.pool.socketCfg.soKeepAlive}") final boolean soKeepAlive) {
     65         return SocketConfig.custom()
     66                 .setTcpNoDelay(tcpNoDelay)
     67                 .setSoReuseAddress(soReuseAddress)
     68                 .setSoTimeout(soTimeOut)
     69                 .setSoLinger(soLinger)
     70                 .setSoKeepAlive(soKeepAlive).build();
     71     }
     72 
     73     /**
     74      * HttpClient连接池管理对象
     75      *
     76      * @param maxTotal                总连接数
     77      * @param defaultMaxPerRoute      每个路由默认连接数,某一个/每服务每次能并行接收的请求数量
     78      * @param validateAfterInactivity 一次连接保留时长,单位s
     79      * @param idleTimeOut             idle超时时间
     80      * @param defaultSocketConfig     默认socket configuration
     81      * @return HttpClient连接池管理对象
     82      */
     83     @Bean
     84     public PoolingHttpClientConnectionManager httpClientPoolManager(
     85             @Value("${httpClient.pool.maxTotal}") final int maxTotal,
     86             @Value("${httpClient.pool.defaultMaxPerRoute}") final int defaultMaxPerRoute,
     87             @Value("${httpClient.pool.validateAfterInactivity}") final int validateAfterInactivity,
     88             @Value("${httpClient.pool.validateAfterInactivity}") final long idleTimeOut,
     89             final SocketConfig defaultSocketConfig) {
     90         Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
     91                 .register("http", PlainConnectionSocketFactory.INSTANCE)
     92                 .register("https", new SSLConnectionSocketFactory(SSLContexts.createSystemDefault()))
     93                 .build();
     94         PoolingHttpClientConnectionManager poolManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
     95         poolManager.setMaxTotal(maxTotal);
     96         poolManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
     97         poolManager.setValidateAfterInactivity(validateAfterInactivity);
     98         poolManager.closeIdleConnections(idleTimeOut, TimeUnit.SECONDS);
     99         poolManager.setDefaultSocketConfig(defaultSocketConfig);
    100         return poolManager;
    101     }
    102 
    103 }
    HttpClientConfig.java

    5. HttpClient工具类

      1 package com.example.httpclientdemo.common.utils.http.client;
      2 
      3 import org.apache.http.HttpEntity;
      4 import org.apache.http.client.methods.*;
      5 import org.apache.http.impl.client.CloseableHttpClient;
      6 import org.apache.http.impl.execchain.RequestAbortedException;
      7 
      8 import java.io.*;
      9 import java.util.stream.Collectors;
     10 
     11 /**
     12  * HttpClient工具类
     13  *
     14  * @author 复姓江山
     15  * @date 2021/02/08
     16  */
     17 public final class HttpClientUtils {
     18 
     19     /**
     20      * header的Content-Type键
     21      */
     22     public final static String HEADER_CONTENT_TYPE = "Content-Type";
     23 
     24     /**
     25      * R3C默认Content_Type
     26      */
     27     public final static String R3C_DEFAULT_CONTENT_TYPE = "application/vnd.api+json";
     28 
     29     /**
     30      * Authorization
     31      */
     32     public final static String HEADER_AUTHORIZATION = "Authorization";
     33 
     34     private HttpClientUtils() {
     35 
     36     }
     37 
     38     /**
     39      * httpClient的响应实体
     40      *
     41      * @param httpClient httpClient对象
     42      * @param request    请求对象
     43      * @return 响应实体
     44      * @throws IOException IO异常
     45      */
     46     private static CloseableHttpResponse httpResponse(CloseableHttpClient httpClient,
     47                                                       HttpUriRequest request) throws IOException {
     48         return httpClient.execute(request);
     49     }
     50 
     51     /**
     52      * get请求
     53      *
     54      * @param httpClient httpClient对象
     55      * @param request    请求对象
     56      * @return 响应实体
     57      * @throws IOException IO异常
     58      */
     59     public static CloseableHttpResponse get(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
     60         assert HttpGet.METHOD_NAME.equals(request.getMethod());
     61         return HttpClientUtils.httpResponse(httpClient, request);
     62     }
     63 
     64     /**
     65      * post请求
     66      *
     67      * @param httpClient httpClient对象
     68      * @param request    请求对象
     69      * @return 响应实体
     70      * @throws IOException IO异常
     71      */
     72     public static CloseableHttpResponse post(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
     73         assert HttpPost.METHOD_NAME.equals(request.getMethod());
     74         return HttpClientUtils.httpResponse(httpClient, request);
     75     }
     76 
     77     /**
     78      * post或patch请求
     79      *
     80      * @param httpClient httpClient对象
     81      * @param request    请求对象
     82      * @return 响应实体
     83      * @throws IOException IO异常
     84      */
     85     public static CloseableHttpResponse postOrPatch(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
     86         if (request instanceof HttpPost) {
     87             assert HttpPost.METHOD_NAME.equals(request.getMethod());
     88         } else if (request instanceof HttpPatch) {
     89             assert HttpPatch.METHOD_NAME.equals(request.getMethod());
     90         } else {
     91             throw new RequestAbortedException("Not post or patch.");
     92         }
     93         return HttpClientUtils.httpResponse(httpClient, request);
     94     }
     95 
     96     /**
     97      * patch请求
     98      *
     99      * @param httpClient httpClient对象
    100      * @param request    请求对象
    101      * @return 响应实体
    102      * @throws IOException IO异常
    103      */
    104     public static CloseableHttpResponse patch(CloseableHttpClient httpClient, HttpUriRequest request) throws IOException {
    105         assert HttpPatch.METHOD_NAME.equals(request.getMethod());
    106         return HttpClientUtils.httpResponse(httpClient, request);
    107     }
    108 
    109     /**
    110      * httpClient的HttpEntity
    111      *
    112      * @param response 响应实体
    113      * @return HttpEntity
    114      */
    115     public static HttpEntity httpEntity(final CloseableHttpResponse response) {
    116         return response.getEntity();
    117     }
    118 
    119 
    120     /**
    121      * 返回状态行代码
    122      *
    123      * @param response 响应实体
    124      * @return 状态行代码
    125      */
    126     public static int getStatusCode(final CloseableHttpResponse response) {
    127         return response.getStatusLine().getStatusCode();
    128     }
    129 
    130     /**
    131      * 获取ContentType
    132      *
    133      * @param httpEntity HttpEntity
    134      * @return ContentType
    135      */
    136     public static String getContentType(final HttpEntity httpEntity) {
    137         return httpEntity.getContentType().getValue();
    138     }
    139 
    140     /**
    141      * 获取ContentEncoding
    142      *
    143      * @param httpEntity HttpEntity
    144      * @return ContentEncoding
    145      */
    146     public static String getContentEncoding(final HttpEntity httpEntity) {
    147         return httpEntity.getContentEncoding().getValue();
    148     }
    149 
    150     /**
    151      * 获取响应体对象InputStream
    152      *
    153      * @param httpEntity HttpEntity
    154      * @return 获取响应体对象InputStream
    155      * @throws IOException IO异常
    156      */
    157     public static InputStream getContent(final HttpEntity httpEntity) throws IOException {
    158         return httpEntity.getContent();
    159     }
    160 
    161     /**
    162      * 获取响应体对象的字符串
    163      *
    164      * @param inputStream InputStream
    165      * @return 获取响应体对象InputStream
    166      * @throws IOException IO异常
    167      */
    168     public static String getContentString(final InputStream inputStream) throws IOException {
    169         return new BufferedReader(new InputStreamReader(inputStream))
    170                 .lines().parallel().collect(Collectors.joining(System.lineSeparator()));
    171     }
    172 
    173     /**
    174      * 获取响应体对象的字符串
    175      *
    176      * @param httpEntity HttpEntity
    177      * @return 获取响应体对象InputStream
    178      * @throws IOException IO异常
    179      */
    180     public static String getContentString(final HttpEntity httpEntity) throws IOException {
    181         return new BufferedReader(new InputStreamReader(HttpClientUtils.getContent(httpEntity)))
    182                 .lines().parallel().collect(Collectors.joining(System.lineSeparator()));
    183     }
    184 
    185     /**
    186      * 字符串转InputStream
    187      *
    188      * @param str 字符串
    189      * @return inputStream
    190      */
    191     public static InputStream stringTransferToInputStream(String str) {
    192         return new ByteArrayInputStream(str.getBytes());
    193     }
    194 
    195     /**
    196      * 设置默认的Content-Type
    197      *
    198      * @param request http请求对象
    199      */
    200     public static void setDefaultContentType(HttpUriRequest request) {
    201         request.setHeader(HttpClientUtils.HEADER_CONTENT_TYPE, HttpClientUtils.R3C_DEFAULT_CONTENT_TYPE);
    202     }
    203 
    204     /**
    205      * 设置Authorization
    206      *
    207      * @param request http请求对象
    208      * @param token   token
    209      */
    210     public static void setAuthorization(HttpUriRequest request, String token) {
    211         request.setHeader(HttpClientUtils.HEADER_AUTHORIZATION, token);
    212     }
    213 
    214     /**
    215      * 设置默认请求头
    216      *
    217      * @param request http请求对象
    218      * @param token   token
    219      */
    220     public static void setDefaultHeader(HttpUriRequest request, String token) {
    221         HttpClientUtils.setDefaultContentType(request);
    222         HttpClientUtils.setAuthorization(request, token);
    223     }
    224 
    225     /**
    226      * 关闭连接
    227      *
    228      * @param response    response响应对象
    229      * @param inputStream inputStream
    230      */
    231     public static void close(CloseableHttpResponse response, InputStream inputStream) throws IOException {
    232         if (inputStream != null) {
    233             inputStream.close();
    234         }
    235         if (response != null) {
    236             response.close();
    237         }
    238     }
    239 
    240 
    241 }
    HttpClientUtils.java

    6. HttpClient业务接口及其实现

     1 package com.example.httpclientdemo.biz.service;
     2 
     3 /**
     4  * HttpClient业务接口类
     5  *
     6  * @author 复姓江山
     7  * @date 2021/02/08
     8  */
     9 public interface HttpClientService {
    10     /**
    11      * get请求
    12      *
    13      * @param url 请求地址
    14      */
    15     void requestGet(String url);
    16 
    17     /**
    18      * post请求
    19      *
    20      * @param url 请求地址
    21      * @param obj 请求对象
    22      */
    23     void requestPost(String url, Object obj);
    24 }
    HttpClientService.java
     1 package com.example.httpclientdemo.biz.service.impl;
     2 
     3 import com.example.httpclientdemo.biz.provider.HttpClientProvider;
     4 import com.example.httpclientdemo.biz.service.HttpClientService;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.stereotype.Service;
     7 
     8 /**
     9  * HttpClient业务接口实现类
    10  *
    11  * @author 复姓江山
    12  * @date 2021/02/08
    13  */
    14 @Service
    15 public class HttpClientServiceImpl implements HttpClientService {
    16 
    17     @Autowired
    18     private HttpClientProvider httpClientProvider;
    19 
    20 
    21     @Override
    22     public void requestGet(String url) {
    23         httpClientProvider.requestGet(url);
    24     }
    25 
    26     @Override
    27     public void requestPost(String url, Object obj) {
    28         httpClientProvider.requestPost(url, obj);
    29     }
    30 }
    HttpClientServiceImpl.java

    7. HttpClient业务支撑接口及其实现

      为什么会加个业务支撑接口呢?常见的分层结构或分层架构(控制层、业务层和数据访问层——分层结构,或表示层(UI)、业务逻辑层(BLL)和数据访问层——分层架构),在此基础上增加provder是因为多层封装与隔离,HttpClient是作为客户端请求其它系统服务,请求参数与相应参数及异常处理应与本项目进行一定隔离,如果把HttpClient客户端深度耦合到业务层中,到对方服务器变动时,就会影响本系统的核心业务逻辑。而增加了封装与隔离后,影响的只是provider层,系统本身的核心业务逻辑不会受到深层次的影响。在这我就稍微发散一下思维,比如定义一个MQ的接口,在使用的是Kafka,RabitMQ,ActiveMQ或者RocketMQ,不管怎么变更MQ,系统业务代码依赖的是MQ的接口,丝毫不会受到影响。所以编程原则里有一条:面向接口编程,面向抽象编程。

     1 package com.example.httpclientdemo.biz.provider;
     2 
     3 /**
     4  * HttpClient业务支撑接口类
     5  *
     6  * @author 复姓江山
     7  * @date 2021/02/08
     8  */
     9 public interface HttpClientProvider {
    10 
    11     /**
    12      * get请求
    13      *
    14      * @param url 请求地址
    15      */
    16     void requestGet(String url);
    17 
    18     /**
    19      * post请求
    20      *
    21      * @param url 请求地址
    22      * @param obj 请求参数
    23      */
    24     void requestPost(String url, Object obj);
    25 }
    HttpClientProvider.java
     1 package com.example.httpclientdemo.biz.provider.impl;
     2 
     3 import com.alibaba.fastjson.JSON;
     4 import com.example.httpclientdemo.biz.provider.HttpClientProvider;
     5 import com.example.httpclientdemo.common.utils.http.client.HttpClientUtils;
     6 import org.apache.http.HttpEntity;
     7 import org.apache.http.client.methods.CloseableHttpResponse;
     8 import org.apache.http.client.methods.HttpGet;
     9 import org.apache.http.client.methods.HttpPost;
    10 import org.apache.http.entity.StringEntity;
    11 import org.apache.http.impl.client.CloseableHttpClient;
    12 import org.slf4j.Logger;
    13 import org.slf4j.LoggerFactory;
    14 import org.springframework.stereotype.Service;
    15 
    16 import javax.annotation.Resource;
    17 import java.io.IOException;
    18 import java.io.InputStream;
    19 import java.nio.charset.StandardCharsets;
    20 
    21 /**
    22  * HttpClient业务支撑接口实现类
    23  *
    24  * @author 复姓江山
    25  * @date 2021/02/08
    26  */
    27 @Service
    28 public class HttpClientProviderImpl implements HttpClientProvider {
    29     private final Logger logger = LoggerFactory.getLogger(this.getClass());
    30 
    31     @Resource(name = "closeableHttpClient")
    32     private CloseableHttpClient httpClient;
    33 
    34 
    35     @Override
    36     public void requestGet(String url) {
    37         HttpGet httpGet = new HttpGet(url);
    38         CloseableHttpResponse response = null;
    39         InputStream inputStream = null;
    40 
    41         try {
    42             response = HttpClientUtils.get(httpClient, httpGet);
    43             HttpEntity httpEntity = response.getEntity();
    44             inputStream = HttpClientUtils.getContent(httpEntity);
    45             String respString = HttpClientUtils.getContentString(inputStream);
    46             logger.debug("respString: {}", respString);
    47         } catch (Exception e) {
    48             e.fillInStackTrace();
    49         } finally {
    50             try {
    51                 HttpClientUtils.close(response, inputStream);
    52             } catch (IOException ioException) {
    53                 ioException.printStackTrace();
    54             }
    55         }
    56     }
    57 
    58     @Override
    59     public void requestPost(String url, Object obj) {
    60         HttpPost httpPost = new HttpPost(url);
    61         String jsonString = JSON.toJSONString(obj);
    62         httpPost.setEntity(new StringEntity(jsonString, StandardCharsets.UTF_8));
    63         CloseableHttpResponse response = null;
    64         InputStream inputStream = null;
    65         try {
    66             response = HttpClientUtils.post(httpClient, httpPost);
    67             HttpEntity httpEntity = response.getEntity();
    68             inputStream = HttpClientUtils.getContent(httpEntity);
    69             String respString = HttpClientUtils.getContentString(inputStream);
    70             logger.debug("respString: {}", respString);
    71         } catch (Exception e) {
    72             e.fillInStackTrace();
    73         } finally {
    74             try {
    75                 HttpClientUtils.close(response, inputStream);
    76             } catch (IOException ioException) {
    77                 ioException.printStackTrace();
    78             }
    79         }
    80     }
    81 }
    HttpClientProviderImpl.java

      8. HttpClient业务接口测试

      通过运行单元测试类来测试接口,下文有详细的测试数据。

     1 package com.example.httpclientdemo.biz.service;
     2 
     3 import org.junit.jupiter.api.Test;
     4 import org.slf4j.Logger;
     5 import org.slf4j.LoggerFactory;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.boot.test.context.SpringBootTest;
     8 
     9 import java.util.concurrent.ExecutorService;
    10 import java.util.concurrent.Executors;
    11 import java.util.concurrent.atomic.AtomicInteger;
    12 
    13 import static org.junit.jupiter.api.Assertions.*;
    14 
    15 @SpringBootTest
    16 class HttpClientServiceTest {
    17     private final static Logger logger = LoggerFactory.getLogger(HttpClientServiceTest.class);
    18 
    19     @Autowired
    20     private HttpClientService httpClientService;
    21 
    22     private static final String URL_GET_PATH = "https://www.baidu.com";
    23 
    24     private final AtomicInteger count = new AtomicInteger();
    25 
    26     /**
    27      * workStealingPool
    28      */
    29     public final static ExecutorService workStealingPool = Executors.newWorkStealingPool(1<<6);
    30 
    31     @Test
    32     void requestGet() throws InterruptedException {
    33         final long startMils = System.currentTimeMillis();
    34         final long statNanos = System.nanoTime();
    35         for (int i = 0; i < 1000; i++) {
    36             workStealingPool.execute(() -> {
    37                 httpClientService.requestGet(URL_GET_PATH);
    38                 logger.warn("requestGet, times: {}, betMils: {},betNanos: {}", count.getAndIncrement(),
    39                         (System.currentTimeMillis() - startMils), (System.nanoTime() - statNanos));
    40             });
    41 
    42         }
    43         Thread.sleep(20000);
    44     }
    45 
    46     @Test
    47     void requestPost() {
    48     }
    49 }
    HttpClientServiceTest.java

    三、测试验证

      本文测试方式可能不是那么专业与严谨,可是并不妨碍我们通过测试数据看出些原理,总结出些规律,也许有些片面,但可看出些趋势。

    1. 运行日志

     1 main 2021-02-09 14:09:34,963 DEBUG (PoolingHttpClientConnectionManager.java:267)- Connection request: [route: {s}->https://www.baidu.com:443][total available: 0; route allocated: 0 of 50; total allocated: 0 of 200]
     2 main 2021-02-09 14:09:34,978 DEBUG (PoolingHttpClientConnectionManager.java:312)- Connection leased: [id: 0][route: {s}->https://www.baidu.com:443][total available: 0; route allocated: 1 of 50; total allocated: 1 of 200]
     3 main 2021-02-09 14:09:34,980 DEBUG (MainClientExec.java:234)- Opening connection {s}->https://www.baidu.com:443
     4 main 2021-02-09 14:09:34,994 DEBUG (DefaultHttpClientConnectionOperator.java:139)- Connecting to www.baidu.com/14.215.177.38:443
     5 main 2021-02-09 14:09:34,994 DEBUG (SSLConnectionSocketFactory.java:366)- Connecting socket to www.baidu.com/14.215.177.38:443 with timeout 0
     6 main 2021-02-09 14:09:35,101 DEBUG (SSLConnectionSocketFactory.java:430)- Enabled protocols: [TLSv1, TLSv1.1, TLSv1.2]
     7 main 2021-02-09 14:09:35,101 DEBUG (SSLConnectionSocketFactory.java:431)- Enabled cipher suites:[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
     8 main 2021-02-09 14:09:35,102 DEBUG (SSLConnectionSocketFactory.java:435)- Starting handshake
     9 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:465)- Secure session established
    10 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:466)-  negotiated protocol: TLSv1.2
    11 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:467)-  negotiated cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    12 main 2021-02-09 14:09:35,250 DEBUG (SSLConnectionSocketFactory.java:475)-  peer principal: CN=baidu.com, O="Beijing Baidu Netcom Science Technology Co., Ltd", OU=service operation department, L=beijing, ST=beijing, C=CN
    13 main 2021-02-09 14:09:35,251 DEBUG (SSLConnectionSocketFactory.java:484)-  peer alternative names: [baidu.com, baifubao.com, www.baidu.cn, www.baidu.com.cn, mct.y.nuomi.com, apollo.auto, dwz.cn, *.baidu.com, *.baifubao.com, *.baidustatic.com, *.bdstatic.com, *.bdimg.com, *.hao123.com, *.nuomi.com, *.chuanke.com, *.trustgo.com, *.bce.baidu.com, *.eyun.baidu.com, *.map.baidu.com, *.mbd.baidu.com, *.fanyi.baidu.com, *.baidubce.com, *.mipcdn.com, *.news.baidu.com, *.baidupcs.com, *.aipage.com, *.aipage.cn, *.bcehost.com, *.safe.baidu.com, *.im.baidu.com, *.baiducontent.com, *.dlnel.com, *.dlnel.org, *.dueros.baidu.com, *.su.baidu.com, *.91.com, *.hao123.baidu.com, *.apollo.auto, *.xueshu.baidu.com, *.bj.baidubce.com, *.gz.baidubce.com, *.smartapps.cn, *.bdtjrcv.com, *.hao222.com, *.haokan.com, *.pae.baidu.com, *.vd.bdstatic.com, click.hm.baidu.com, log.hm.baidu.com, cm.pos.baidu.com, wn.pos.baidu.com, update.pan.baidu.com]
    14 main 2021-02-09 14:09:35,251 DEBUG (SSLConnectionSocketFactory.java:488)-  issuer principal: CN=GlobalSign Organization Validation CA - SHA256 - G2, O=GlobalSign nv-sa, C=BE
    15 main 2021-02-09 14:09:35,254 DEBUG (DefaultHttpClientConnectionOperator.java:146)- Connection established 192.168.100.24:63820<->14.215.177.38:443
    16 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:255)- Executing request GET / HTTP/1.1
    17 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:260)- Target auth state: UNCHALLENGED
    18 main 2021-02-09 14:09:35,255 DEBUG (MainClientExec.java:266)- Proxy auth state: UNCHALLENGED
    19 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:133)- http-outgoing-0 >> GET / HTTP/1.1
    20 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Host: www.baidu.com
    21 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Connection: Keep-Alive
    22 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> User-Agent: Apache-HttpClient/4.5.12 (Java/1.8.0_161)
    23 main 2021-02-09 14:09:35,257 DEBUG (LoggingManagedHttpClientConnection.java:136)- http-outgoing-0 >> Accept-Encoding: gzip,deflate
    24 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "GET / HTTP/1.1[
    ][
    ]"
    25 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Host: www.baidu.com[
    ][
    ]"
    26 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Connection: Keep-Alive[
    ][
    ]"
    27 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.12 (Java/1.8.0_161)[
    ][
    ]"
    28 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Accept-Encoding: gzip,deflate[
    ][
    ]"
    29 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "[
    ][
    ]"
    30 main 2021-02-09 14:09:35,300 DEBUG (Wire.java:73)- http-outgoing-0 << "HTTP/1.1 200 OK[
    ][
    ]"
    31 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Encoding: gzip[
    ][
    ]"
    32 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Length: 1145[
    ][
    ]"
    33 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Type: text/html[
    ][
    ]"
    34 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Server: bfe[
    ][
    ]"
    35 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Date: Tue, 09 Feb 2021 06:09:34 GMT[
    ][
    ]"
    36 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[
    ][
    ]"
    37 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x1f][0x8b][0x8][0x0][0x0][0x0][0x0][0x0][0x0][0xff][0x94]V[[0x8f][0xd4][0xb6][0x17]G[0xe2];[0x98][0xfc][0xb5][0xbb] 4[0xe3][0xb9][0x8][0xc1]7[0x9][0xda]nABH[0x5][0x15]V*O#[0xc7]v[0x12][0xb3][0x89]mlg[0xc2][0xf0][0xd4][0x95]J[0xd5][0xaa][0xa5][0xb4][0xa2][0x17]Q*[0xb5][0xaa]Z[0xb6][0xf][0x95][0xa0]*R[0xd1]R[0xe0][0xcb]L[0xd8][0xdd][0xa7]~[0x85][0xca]If[0xe7][
    ]"
    38 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0xa8][0xf3][0x12][0xfb][0xf8][0x9c][0xdf][0xf9][0x9d][0x9b]=[0xee][0xb1]w/m[0xbd]v[0xf9][0x1c][0x88]M[0x9a][0xf8]G[0x8f][0xb8][0xc7][0x1a][0x8d]+W[0xd7][0xaf]n^[0x1][0x97].6[0x1a][0xbe][[0xca][0x81][0x1b]SD|7[0xa5][0x6][0x81][0xd8][0x18][0xd9][0xa0]72[0xd6][0xf7][0xb0][0xe0][0x86]r[0xd3]0[0x3]IA[0xbd][0xf1][0xc][0xbd]i[0xa0]5[[0xc3]1R[0x9a][0x1a]/3a[0xe3][0xcc][0xbc][0xf5][0x7][0x8d][0xcd][0xf5][0xc6][0x86]H%2,H[0xc6][0x0][0x17][0xce]y[0xe7]HDk[0x83][0x91][0x14]%9[0x1a]h[0xc0]QJ=EC[0xaa][0x14]U[0xbe][0x9b]0[0xbe][0x5][0x14]M<m[0x6][0x9][0xd5]1[0xa5][0x6]X6[0x15][0xb][0xac]5[0x88][0x15][
    ]=[0xeb]U[0xaf]B[0xa8]u[0xbb][0x19][0x10]m[0x90]a[0xb8][0x89]E[
    ]"
    39 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "O[0xd1][0xf7][0xda][0xc1][0xf5][0x1b]g[0xd6][0xd7]7[0xaf][0xa5][0x9d][[0x91][0xb8][0xd6][0xbd][0x8][0x15][0xcc][0xf3][0x1c]b[0x84]c[
    ]"
    40 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x3]"[0xd4]-[0x18] F[0xb2]f[0xca]x[0x13]k[0xed][0xbb][0x86][0x99][0x84][0xfa]{[0xf7]_[0x14][0xbb][0xf][0x87]O?[0x1c]>[0xfd][0xec][0x9f][0xbf]?[0x1f]>[0xff][0xa9]x[0xfc][0xc7][0xde][0x8f][0xbf][0x1e]l[0xdf]sa[0xa5][0xe2][0xc2]2q[0xc0][
    ][0x4][0x19][0x0]K[0xd6][0xfb]_[0xab][0xd5]ja[0xec][0x3][0x97][0xb0]>`[0xc4][0xcb][0x15][0x92][0x92][0xaa][0xb1][0xa0]6[0xb1];[0x9c] [0xad]KAoZ[0xad]:[0xd0][0xbd]P[0xa8]t[0x81][0xa8]7[0x7][0x9a]D>pY[0x1a][0x81][0x98][0x11][0x1a][
    ]"
    41 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "[0x9c]i[0xcf][0xa8][0x8c][0x2][0xad][0xb0][0x7]m[0xbc][0xcd]*F[0x9b][0x14][0x96]F0 [0xbd]DD[0xa2][0xdd][0x94]<[0x2]9#&[0xf6]:[0xa7][ [0xa6],[0x8a][0x8d][0xd7][0xee][0xfc][0xdf][0x7].$[0xac][0xef][0x3][0xd7]:[0xb4].[0xca]oY[0x9f][0x10] l[0x98][0xe0]s[0xc8][0xba]f[0x19]Z[0xd2][0x8c][0xcb][0xac][0xae]V[0xcc][0x8][0xa1][0xbc]2.3[0xde][0xc3]"[0xa5][0xa0][0x8f][0x92][0x8c]z[0xed][0xd7][0xeb][0xb2][0x91]N[0xd5]b[0xaf][0xd5][0xb]k[0xb5]7[0xa8]([0xdd][0xef][0x5][0xf2][0xed].[0xad][0x1e]#7[0xdf][0xae]hx[0xad]S[0x86][0xef][0xbb]Z"^[0x87][0xef][0x4][0x11][0xd0]=&M/W[0x8e]_[0x3]0[0xe2]m[0xe5][0x95]iN[0xe][0xab][0xc9][0xa4][0xa9]`@[0x8a]n&[0x94]G[0xb6][0x10][0xa7]N[0x1][0x94][0x19][0x81]E*[0x13]j[0xa8]'[0xc2][0xb0][0x14]Tu=[0xf9].[0xb4]N[0x17][0xb8][0xe][0xc][0x9f]t]r[0xd7]Y[0x90][0xb2][0x92][0x86][0xce]j[0xe6][0x93][0x1d]>k[0xef][0x80]9?[0xc0][0x85]u?[0xd6][0x9d]Q[0xea][0x16][0xcc]l[0xb2][0xd0]x W![0xe4]4[0xd7][0xe3][0xf6][0xa8][0xf3]v[0xbd]g[0x94]=[0xa8]=[0xa6][0x1c][0xf5][0xfd]W[0xdf]>>[0xf8][0xee][0x99][0xb][0xd1]4[0x84][0x9d]i[0xdb]a1[0x12][0xed]Nw[0x6][0xa3][0x12]N[0xa2]T[0x92]9[0x94]U[0x8]S$[0x17][0xf2]H[0x91][0x9c][0x4](~x<x[0xb1][0x8][0xa0][0xbf][0xd0][0xbc][0xcf][0x8][0x15][0x93][0x0][0xfb];[0x1f][0x1f][0xfc][0xfc][0xd5]"[0x0][0xc3]h[0x80][0x16][0x82][0x94]'S O[0x9e][0x14]_[0xee]T h[0xac][0x98]4sx[0xd3][0x83]W]c[0x89][0x88][0x18]oF,<[[0xae][0x96]Q*[0xd7][0x8c]L[0xbc][0xb4]Zf[0xa5][0xed]Rw}[0xa9]s~[0xa9]s~[
    ]"
    42 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "a[0xa9][0x13].u[0xc3][0xf1]l.uI[0xfb][0x90]c[0x89]V3L[0x2][0xef][0xfe][0xb3][0xe2][0xf9]7[0x15]?8A[0xb0]^[0x10][0x81][0xb3][0x94]r[0xd3][0xcc][0x15]3[0xf4][0xf8][0xca][0x88][0xb8][0xf3][0x1f][0x98][0xd7][0xac]3o[0xe5]$[0xa0][0x1c][0xb]B7[0xdf][0xbf]`[0xdf][0x12][0xc1])7[0xc7]s[0xc6][0x89][0xc8][0x9b][0x89][0xc0][0xc8][0xde]CM[0x8b][0x12][0xcc][0x89]5E[
    ]"
    43 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:73)- http-outgoing-0 << "[0xc7][0xc0][0xf3]<[0xe0]8[0xe0],p[0xce]:`[0x15]8[0xcb][0xce][0x89][0x93][0xc0][0x19][0xc7][0xea][0xb5][0xad]`[0xc5][0xa9][0xe2]uF[0x1];[0xa3][0x91]H[0x2]g"[0xe6][0x95][0x13]kG[0x8f][0x80][0x99][0x9f][0xb]g[0xcb]4[0x1b]g*[0x14][0x85][0x87][0x19][
    ][0x14]cX[0x8c]r[0x1a]([0x6][0xca][0x7][0xce]s[0x8][0xd3]2A[0x83]U[0x10]$[0x2]o[0xad]9[0xfe][0xab][0x7]O[0x8a]_[0xbe][0x1f][0xee][0xee][0x14][0xf7][0xb6][0xeb][0x94]O[
    ][0xdf][0xf4][0xc][0x86]fC[0xf0][0x99]m[0xee][0x3]W[0x96]oD<[0xd7]E[0xb1]H[0xe9][0x98][0xa4]_[0xdc][0xfe]s[0xb8][0xfb]Eu-,jb[0xa6]&[0x94][0xd7][0x3][0x91][0x19][0xf0][0x8e][0xdd][0xd7][0xc4][0xe4][0xc8][0x13][0x96][0xfe]2[0x16]r[0xb0][0xd6]i[0xb5]O/[0xf3]@[0xcb][0xb5]R[0xaf]Z[0xbe][0xb1][0x93]If[0x6][0xd0][0x1f]>[0xb9][0xf7][0xf5]o[0x15][0x91][0xe2][0xd3];[0xc5][0xcb][0xdb][0xfb][0x8f][0xca][0xeb][0xa1]B[0x98][0xe5]u[0x9d]!>`[0x13](ub[0xb1]l[0x84][0x94][0x92][0x0][0xe1]-[0xff][0xd5]Gw[0xf7]w[0xb6][0x8b][0xbb]w[0xe][0x1e]~2F[0x1a][0xee][0xfe]~a[0xe3][0xf2][0xfe][0xa3][0xed]V[0xb7][0xd5]>[0xdd]-[0xee][0xfe]5[0xf2]`[0x1f][0xd3][0xd7][0xbd][0x9e][0x91][0xb6][0xbd]:[
    ]"
    44 main 2021-02-09 14:09:35,303 DEBUG (Wire.java:87)- http-outgoing-0 << "yaA[0xa0][0xfd]K`[0xbf][0xf5]?[0xaf][0x3][0x0][0x0][0xff][0xff]0[0xc][0x81][0x9a][0x8b][0x9][0x0][0x0]"
    45 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:122)- http-outgoing-0 << HTTP/1.1 200 OK
    46 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Encoding: gzip
    47 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Length: 1145
    48 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Content-Type: text/html
    49 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Server: bfe
    50 main 2021-02-09 14:09:35,306 DEBUG (LoggingManagedHttpClientConnection.java:125)- http-outgoing-0 << Date: Tue, 09 Feb 2021 06:09:34 GMT
    51 main 2021-02-09 14:09:35,310 DEBUG (MainClientExec.java:285)- Connection can be kept alive indefinitely
    52 main 2021-02-09 14:09:35,316 DEBUG (HttpClientProviderImpl.java:46)- respString: <!DOCTYPE html>
    53 <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');
    54                 </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a>&nbsp;京ICP证030173号&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
    55 main 2021-02-09 14:09:35,318 DEBUG (PoolingHttpClientConnectionManager.java:344)- Connection [id: 0][route: {s}->https://www.baidu.com:443] can be kept alive indefinitely
    56 main 2021-02-09 14:09:35,318 DEBUG (LoggingManagedHttpClientConnection.java:88)- http-outgoing-0: set socket timeout to 0
    57 main 2021-02-09 14:09:35,318 DEBUG (PoolingHttpClientConnectionManager.java:351)- Connection released: [id: 0][route: {s}->https://www.baidu.com:443][total available: 1; route allocated: 1 of 50; total allocated: 1 of 200]
    58 main 2021-02-09 14:09:35,319 WARN (HttpClientServiceTest.java:80)- requestGet, times: 0, betMils: 403,betNanos: 402522300
    httpClientLog

    2. 综合比较

      maxTotal:200

    Threads

    defaultMaxPerRoute

    validateAfterInactivity

    betMils

    betNanos

     256

     20

     1500

     5270

    5269994599 

     50

     

    4310

     

    4310753100

     

    100

     

    4513

     

    4512503700

     

    150

     

    4963

     

    4962632601

     

    200

     

    5245

     

    5244764201

     

    1024

     

     

    20

     1500

     

    5087

     

    5087564601

     

    50

     

    4323

     

    4323088301

     

    64

      

     

    50

      

     

    15000

     

    3900

     

    3900514800

     

    2000(default)

     

    3531

     

    3537111900

    0

    3358

    3355394500

    32

     

    50

     

    0

    3471

     

    3456438200

     

    2000(default)

     

    2918

     

    2912550800

     50

     50

     

    15000

     

    2847

     

    2846675400

    0

    3190

    3189325400

    2000(default)

    3263

    3264044800

    1000

    2741

    2740233600

    500

    2802

    2801841600

    800

     

    2800

     

    2800641400

      

      根据以上数据我们能看出什么呢?

      在分析数据以前我先罗列一下电脑配置:

      Windows 10 专业版

      Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz 3.00 GHz 4核

      16.0 GB

      64 位

      SSD 232.89 GB

      首先根据本机硬件及系统配置,多线程可以提高系统的并发效率,但是也不是绝对的,大致在50个线程的时候效果较好。然后defaultMaxPerRoute参数也是50,即每个路由默认并行接受的请求数。因为本文的测试目标服务器是百度,百度服务器设置连接时间可无限期的保持“Connection can be kept alive indefinitely”,调节validateAfterInactivity参数,总的来说效果不是很大,当然需要排除网络请求的一些影响因素,比如拥塞、路由等情况,可根据下表的参数比较知道,即使相同的配置参数,不同时间点请求服务器,响应的时长也有差异,也就是说每一次的网络请求都是必然中的一次偶然情况。

    3. 同参数比较

      Threads: 50 

      maxTotal: 200

      defaultMaxPerRoute:50

      validateAfterInactivity:1000

      idleTimeOut:3

    betMils

    betNanos

    2813

    2813779600

    3228

    3229129100

    3030

    3030484200

    2806

    2805046900

    2981

    2981383600

    2629

    2629455200

    2814

    2813863100

    2747

    2747754700

    2748

    2747132800

    3365

    3365044500

      通过上表可以看出,每一次网络请求在同一网络情况下或相似网络情况下,响应的时长差距不大。但因为影响网络的因素众多,导致每次响应的时长都不一样。

     四、后记

      暂时先分享到此,后期会有补充的,比如源码、架构等。

    不忘初心,不忘本谋
  • 相关阅读:
    mysql 版本查看
    js 中文乱码
    浏览器内核
    Squid 代理服务器
    minicygwin
    firefox 插件开发
    ocx c++
    NetBeans
    android 虚拟机
    ExpandableListView
  • 原文地址:https://www.cnblogs.com/inverseEntropy/p/14392453.html
Copyright © 2011-2022 走看看