问题描述
用 resttemple 进行http请求,访问内网的另一个服务,在并发(100)的情况,会出现部分请求阻塞,耗时到达4~5秒左右。已排除被调用方的问题。单独压测被调用方,1000并发耗时都没有超过500毫秒的。用skywalking追踪,发现耗时高的请求都在socketread0 这个方法。
这是resttemple 的配置
@Component
public class WebConfig {
/**
* 基于OkHttp3配置RestTemplate
* @return
*/
@Bean
public RestTemplate restTemplate() {
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(3, TimeUnit.SECONDS).readTimeout(5,TimeUnit.SECONDS).addInterceptor(new LoggingInterceptor()).build();
okHttpClient.dispatcher().setMaxRequests(4000);
okHttpClient.dispatcher().setMaxRequestsPerHost(3000);
return new RestTemplate(new OkHttp3ClientHttpRequestFactory(okHttkbpClient));
}
}
已确定配置正常使用,并且正常注入。
被调用方返回的数据很小,只有几kb
后来我用本地测试 ,本地调本地的应用,被调用方只返回一个“成功”,在模拟100并发的情况,也会出现耗时1秒左右的情况。
请问这是什么原因,有什么解决方法吗
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(httpRequestFactory());
}
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
//设置整个连接池最大连接数 根据自己的场景决定
connectionManager.setMaxTotal(4000);
connectionManager.setDefaultMaxPerRoute(1000);
//路由是对maxTotal的细分
connectionManager.setDefaultMaxPerRoute(1000);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(10000) //服务器返回数据(response)的时间,超过该时间抛出read timeout
.setConnectTimeout(10000)//连接上服务器(握手成功)的时间,超出该时间抛出connect timeout
.setConnectionRequestTimeout(10000)//从连接池中获取连接的超时时间,超过该时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
}
socketread0
,这个是apache httpclient
可能发生的问题,无限等待响应导致线程卡死。实际上请求因为各种原因已经无法获取到响应了,比如并发过高导致远端服务无法响应。
这里应该添加一个httpclient的socket配置,设置等待时间,可以避免线程卡死的问题,超时后继续返回结果,设置类似下面,SoTimeout就是超时时间参数