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>
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
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 }
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 }
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 }
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 }
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 }
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 }
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 }
三、测试验证
本文测试方式可能不是那么专业与严谨,可是并不妨碍我们通过测试数据看出些原理,总结出些规律,也许有些片面,但可看出些趋势。
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[\r][\n]" 25 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Host: www.baidu.com[\r][\n]" 26 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]" 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)[\r][\n]" 28 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]" 29 main 2021-02-09 14:09:35,258 DEBUG (Wire.java:73)- http-outgoing-0 >> "[\r][\n]" 30 main 2021-02-09 14:09:35,300 DEBUG (Wire.java:73)- http-outgoing-0 << "HTTP/1.1 200 OK[\r][\n]" 31 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Encoding: gzip[\r][\n]" 32 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Length: 1145[\r][\n]" 33 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Content-Type: text/html[\r][\n]" 34 main 2021-02-09 14:09:35,301 DEBUG (Wire.java:73)- http-outgoing-0 << "Server: bfe[\r][\n]" 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[\r][\n]" 36 main 2021-02-09 14:09:35,302 DEBUG (Wire.java:73)- http-outgoing-0 << "[\r][\n]" 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][\n]" 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][\r]=[0xeb]U[0xaf]B[0xa8]u[0xbb][0x19][0x10]m[0x90]a[0xb8][0x89]E[\n]" 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[\n]" 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][\r][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][\n]" 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~[\n]" 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[\n]" 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][\r][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[\r][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]:[\n]" 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&tpl=mn&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>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <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
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 |
通过上表可以看出,每一次网络请求在同一网络情况下或相似网络情况下,响应的时长差距不大。但因为影响网络的因素众多,导致每次响应的时长都不一样。
四、后记
暂时先分享到此,后期会有补充的,比如源码、架构等。