在高并发请求下面,使用RestTemplate 作为请求链接会抛出 java.net.BindException Address alreadly in use coonetc ,主要原因是短时间内Socket 创建链接过多,动态绑定端口被使用尽,高频并且短的请求,在Socket.close()操作之后,协议并不会立即释放绑定的端口,将端口设置为TIME_WAIT状态,过240秒之后才会释放,这个通过netstat -na 查看到往目标机器发送时候查看到大量处于TIME_WAIT状态的端口,最后导致系统的资源耗尽 ,及时WINDOW SERVER 上 启动端口49152(16384)。
解决方法: 使用RestTemplate 换一种请求方式,使用链接池方式进行配置:
1.Restemplate 提供两种工厂模式实现请求接口
1). SimpleClientHttpRequestFactory, 底层使用J2SE (java.net包提供方式) 创建HTTP请求,大多数访问量不高时候
2). HttpComponentsClientHttpRequestFactory 底层使用HttpClient访问远程HTTP服务请求,使用HTTPClient可以配置链接池。 具体配置如下,配置成功后对于高频且短的大量Request请求,控制 Request的请求量,不会跑出IntAddress use out的异常。
package com.huawei.similar.dts.vocab.config;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.TimeUnit;
/**
* HttpComponentClientHttpRequestFactory 设置时间
*
* */
public class RestTemplateConfig {
private static RestTemplate restTemplate;
static {
// 长链接保持时间长度20秒
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager(20, TimeUnit.SECONDS);
// 设置最大链接数
poolingHttpClientConnectionManager.setMaxTotal(2*getMaxCpuCore() + 3 );
// 单路由的并发数
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(2*getMaxCpuCore());
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
// 重试次数3次,并开启
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3,true));
HttpClient httpClient = httpClientBuilder.build();
// 保持长链接配置,keep-alive
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
// 链接超时配置 5秒
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
// 连接读取超时配置
// httpComponentsClientHttpRequestFactory.setReadTimeout(10000);
// 连接池不够用时候等待时间长度设置,分词那边 500毫秒 ,我们这边设置成1秒
httpComponentsClientHttpRequestFactory.setConnectionRequestTimeout(3000);
// 缓冲请求数据,POST大量数据,可以设定为true 我们这边机器比较内存较大
httpComponentsClientHttpRequestFactory.setBufferRequestBody(true);
restTemplate = new RestTemplate();
restTemplate.setRequestFactory(httpComponentsClientHttpRequestFactory);
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
}
public static RestTemplate getRestTemplate(){
return restTemplate;
}
private static int getMaxCpuCore(){
int cpuCore = Runtime.getRuntime().availableProcessors();
return cpuCore;
}
}