问题描述:使用Apache的HttpClient实现发送TCP请求,当每秒的并发量变大时就会出现无端口可用的情况,查看服务器端口使用情况发现大量处于TIME_WAIT状态,这就导致并发量受限。
部分代码:
/**
* created on 2018年4月17日 下午2:28:27
*/
import java.io.IOException;
import java.net.URI;
import java.time.Instant;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import cn.utstarcom.gltctest.common.GltcTestCache;
/**
* @author 随心行
* @date 2018年4月17日
*
*/
public class ApacheHttpClientTask {
// @Value("${client.clientHeader}")
private static String clientHeaderName = "X-Forwarded-For";
private CloseableHttpClient httpClient;
private HttpGet httpGet;
private String clientIp;
private String httpUri;
private static RequestConfig requestConfig;
private static final Logger logger = LoggerFactory.getLogger(ApacheHttpClientTask.class);
static {
requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000)
.setRedirectsEnabled(false).build();
}
public ApacheHttpClientTask(String httpUri, String clientIp) {
this.clientIp = clientIp;
this.httpUri = httpUri;
httpClient = HttpClients.createSystem();
httpGet = new HttpGet();
httpGet.setConfig(requestConfig);
httpGet.setURI(URI.create(httpUri));
httpGet.setHeader(clientHeaderName, clientIp);
}
public void execute() {
CloseableHttpResponse response = null;
countSendNum();
try {
logger.debug("client ip: {} , http uri: {}", clientIp, httpUri);
response = httpClient.execute(httpGet);
//响应处理部分
} catch (IOException e) {
logger.error("clientIP: {} ,uri: {}", clientIp,
httpGet.getURI(), e);
} finally {
try {
if (response != null)
response.close();
// httpGet.releaseConnection();
if (httpClient != null)
httpClient.close();
} catch (IOException e) {
logger.error("exception message");
}
}
}
}
解决方法:出现问题就在网上查询各种解决办法,不断尝试后最终使用httpGet.setHeader(HttpHeaders.CONNECTION, "close"),改用短链接(HttpClient默认使用长链接),客户端不在关闭注释掉finally中关闭部分的代码。
public ApacheHttpClientTask(String httpUri, String clientIp) {
this.clientIp = clientIp;
this.httpUri = httpUri;
httpClient = HttpClients.createSystem();
httpGet = new HttpGet();
httpGet.setConfig(requestConfig);
httpGet.setURI(URI.create(httpUri));
httpGet.setHeader(clientHeaderName, clientIp);
httpGet.setHeader(HttpHeaders.CONNECTION, "close");//由服务端关闭
}
public void execute() {
CloseableHttpResponse response = null;
countSendNum();
// try (httpClient; CloseableHttpResponse response =
// httpClient.execute(httpGet);) {
try {
logger.debug("client ip: {} , http uri: {}", clientIp, httpUri);
response = httpClient.execute(httpGet);
//响应处理
} catch (IOException e) {
countFailNum();
logger.error("clientIP: {} ,uri: {}", clientIp,
httpGet.getURI(), e);
} // 去掉finally关闭部分
}
通过命令netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 或ss -an | grep 服务端端口 | wc -l 可以看到TIME_WAIT数量不在持续增加。
参考资料:https://www.cnblogs.com/sunxucool/p/3449068.html
https://doc.nuxeo.com/blog/using-httpclient-properly-avoid-closewait-tcp-connections/
https://blog.csdn.net/qq_16097611/article/details/78095838