RestTemplate 链接池:记一次压测调优

[ 用大白话讲解复杂的技术 ]java

这是个人第 53 篇原创文章
做者 l 会点代码的大叔(CodeDaShu)   


最近工做上有些调整,进入了另外一个项目组,本周在给一个接口作压力测试的过程当中,发现 TPS 波动比较大:单台服务器的 TPS 在 1000 到 200 之间波动,发现问题后咱们作了这几件事儿逐一排问题。web


1. 排除其余操做对压测的影响数据库

观察数据的时间戳,发如今压测过程当中有频发的数据写入,先暂停跑批操做,再次压测波动依然存在;apache


2. 代码检查,下降数据库查询次数服务器

作代码检查,这个功能须要查询六次数据库、调用一次接口才能得到全部数据,通过优化后将查询数据库的次数下降为三次,再次压测后 TPS 有所提高,可是波动的状况还存在;微信


3. 分阶段压测,缩小问题范围app

由于该接口的逻辑是本地逻辑 + 远程调用,因而先作了挡板单压本地逻辑,再单独压远程接口,两次压测不存在波动的问题,因此基本上能够肯定是调用接口的过程当中存在一些问题;框架


4. 排除 GC 问题编辑器

调用接口的过程当中建立了太多的 Java 对象,可能会引起频发的 GC 操做;可是经过对 JVM 的观察排除了这个问题;ide


5. 初步确认问题

最后将问题的范围缩小,怀疑是 RestTemplate 的使用问题;


RestTemplate 是 Spring 提供的用于访问 Http 接口的客户端框架,可以大大提升客户端的编写效率,大部分基于 SSM 或 Spring Boot 的项目会使用 RestTemplate,翻了一下项目中 RestTemplate Config,只配置了超时时间:

@Configurationpublic class RestTemplateConfig { @Bean public RestTemplate restTemplate(){ SimpleClientHttpRequestFactory factory =new SimpleClientHttpRequestFactory(); factory.setConnectTimeout(30000); factory.setReadTimeout(10000); RestTemplate restTemplate = new RestTemplate(factory); return restTemplate; }}


RestTemplate 默认的 

ClientHttpRequestFactor 

SimpleClientHttpRequestFactory,其中的 createRequest 方法,每次都会建立一个新的链接,创建链接自己就是一个费时费力的操做,若是频繁地对一个接口发起调用,每次都建立链接会形成极大的资源浪费,并且若链接不能及时释放,就会由于没法创建新的链接致使后面的请求阻塞。

@Overridepublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException { HttpURLConnection connection = openConnection(uri.toURL(), this.proxy); prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) { return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming); } else { return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming); }}


看到这种状况处理起来也算简单:弄个链接池


建立 RestTemplate链接线程池,就须要使用其余的 HTTP 库(默认使用的是 JDK 本身的),好比 HttpComponents、Netty、OkHttp,在这里我选择的是 HttpComponents 。


1. 引入依赖:

<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version></version></dependency>
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version></version></dependency>


2. 修改 RestTemplateConfig :

@Configurationpublic 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(400); //路由是对maxTotal的细分 connectionManager.setDefaultMaxPerRoute(100); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(30000) //返回数据的超时时间                .setConnectTimeout(10000//链接上服务器的超时时间 .setConnectionRequestTimeout(1000) //从链接池中获取链接的超时时间 .build(); return HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(connectionManager) .build(); }}


修改完成以后再次压测,单机 TPS 稳定在 1200,打完收工。


期待分享

若是您喜欢本文,请点个“在看”或分享到朋友圈,这将是对我最大的鼓励。



本文分享自微信公众号 - 会点代码的大叔(CodeDaShu)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索