本文是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[\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
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 |
通过上表可以看出,每一次网络请求在同一网络情况下或相似网络情况下,响应的时长差距不大。但因为影响网络的因素众多,导致每次响应的时长都不一样。
四、后记
暂时先分享到此,后期会有补充的,比如源码、架构等。