概述
今天在使用HttpClient
进行 远程调用测试
调用两个服务,一个在同一个集群,一个在不同的集群
想测试一下,看下不同集群寻址耗时到底有多大
没想到,这个过程中,遇到了很多问题,一一解决之后,在此记录一下,分享出来
无响应
第一版代码
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final HttpClient CLIENT = HttpClientBuilder.create().build;
public static void main(String[] args) throws Exception {
HttpGet httpGet = new HttpGet(url);
long begin = System.currentTimeMillis();
HttpResponse response = CLIENT.execute(httpGet);
long gap = System.currentTimeMillis() - begin;
int statusCode = response.getStatusLine().getStatusCode();
LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
}
代码写好之后,在postman
里配置好,随手点了两下,发现点多了就有点卡,
现象就是过了好久都没有响应
猜测是不是网络出了问题,超时了,于是网上搜了搜,加了三个超时时间
对client 更新一下
private static final HttpClient CLIENT;
static {
RequestConfig config = RequestConfig.custom()
.setConnectionRequestTimeout(1000) //从连接池中获取连接的超时时间
.setConnectTimeout(300) // 与服务器连接超时
.setSocketTimeout(300) // 读取服务器返回的数据 超时
.build();
CLIENT = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.build();
}
第一次 ConnectionPoolTimeoutException
client
各种超时时间设置好后,的确不再很长时间无响应
,但是点到第三次
直接就抛异常 ConnectionPoolTimeoutException
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:286)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
搜了一圈,发现这个异常是因为 HttpClient
默认的 连接池 数量为 2
,当连接池用完之后,拿不到连接且达到超时阈值,就会抛异常
那么我就把这个数量改大点,并且主动调用 abort
方法
相关博客
https://blog.csdn.net/shootyou/article/details/6615051
https://blog.csdn.net/shootyou/article/details/6415248
代码更新
client
private static final HttpClient CLIENT;
static {
RequestConfig config = RequestConfig.custom()
.setConnectionRequestTimeout(1000) //从连接池中获取连接的超时时间
.setConnectTimeout(300) // 与服务器连接超时
.setSocketTimeout(300) // 读取服务器返回的数据 超时
.build();
//参数含义参考 下面两个博客
//https://blog.csdn.net/shootyou/article/details/6615051
//https://blog.csdn.net/shootyou/article/details/6415248
CLIENT = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setMaxConnTotal(800) //设置最大连接数,默认值是2
.setMaxConnPerRoute(400) //每个路由最大连接数(一个网址就是一个连接)
.build();
}
HttpGet
public static void main(String[] args) throws Exception {
HttpGet httpGet = new HttpGet(url);
long begin = System.currentTimeMillis();
HttpResponse response = CLIENT.execute(httpGet);
long gap = System.currentTimeMillis() - begin;
int statusCode = response.getStatusLine().getStatusCode();
LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
//主动终止连接
httpGet.abort();
}
第二次 ConnectionPoolTimeoutException
这次代码改好之后,随便点了点,貌似不再出问题了
心理窃喜,于是上 jmeter
和 postman
批量进行测试
这是 jmeter
响应时间图
![](https://img.haomeiwen.com/i13864094/522289caf2f92e82.png)
这个图的末尾怎么出现了这么离谱的离散点?
于是手动用postman
再次测了测
再次抛出了异常 ConnectionPoolTimeoutException
用前面博主的命令 去机器上执行,TIME_WAIT
数量也一直很小,陷入了僵局
[root@cf6d9e5767eb94c7e857cd35600149344-node3 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 42
TIME_WAIT 78
解决
中文资料搜了一堆,发现都是抄来抄去,也没有什么干货
于是转英文
这个回答的意思就是说,reponse的 entity 需要被消费,且相关的流需要被关闭,
并且给出了工具类
EntityUtils.consumeQuietly(response.getEntity());
更新我的代码
public static void main(String[] args) throws Exception {
HttpGet httpGet = new HttpGet(url);
long begin = System.currentTimeMillis();
HttpResponse response = CLIENT.execute(httpGet);
long gap = System.currentTimeMillis() - begin;
int statusCode = response.getStatusLine().getStatusCode();
LOGGER.info("type {}, response code {}, gap {}", type, statusCode, gap);
//主动终止连接
httpGet.abort();
//把 reponse 的流 消费一下
EntityUtils.consumeQuietly(response.getEntity());
}
测试了一下,终于OK了
最后来张 JMeter
图
![](https://img.haomeiwen.com/i13864094/0795fdbf4606f030.png)
网友评论