- 前言
就在昨天线上的X服务调用的Y服务需要上线,然后Y服务的ng路由做了改动。然后A服务的RestTemplate调用Y服务的某个接口开始报400!
刚刚开始我们以为是ng路由配置的问题,因为我们X服务并没有做上线,之前也运行平稳,所以我们就下意识的认为应该是Ng配置的原因。但是当Ng配置还原之后,问题并没有解决,仍旧是400!
然后我们直接在X服务器上用curl访问Y服务的接口,访问正常!所以排除X服务问题,那么只有可能是X服务出问题。但是X服务一直并没有做上线呀,为什么ng做了改动就这样了呢!
后面一直没找到问题,无奈之下重启了服务,问题不再出现!
- 思考
整个自我的测试流程下来,其实基本可以定位到是A服务的问题,虽然他并没有做改动,但是肯定是外部的环境导致了A服务某个地方出现了问题。随后,我们定位到了RestTemplate这个点!
疯狂找问题中。。。。
loading。。。。
最后发现我们是将RestTemplate设置成了单例,然后初始化的时候用了HttpComponentsClientHttpRequestFactory。用这个是为了配置RestTemplate调用的时候的超时配置。
这个时候问题就来了!
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
由于我是这样实例化HttpComponentsClientHttpRequestFactory,可以看到源码是:
由图可知HttpComponentsClientHttpRequestFactory默认用的是HttpClient,然后他的一个构建工厂HttpClientBuilder有一个属性是systemProperties。再看下面的源码:
当systemProperties这个属性为true的时候,HttpClient保持长连接了,而且接下去他会使用默认一个重用策略DefaultClientConnectionReuseStrategy。。。
坑爹啊,留下悔恨的眼泪。。。。
- 定位
所以也就是说当我使用默认的初始化HttpComponentsClientHttpRequestFactory的时候,他默认会使用HttpClient的长连接。此时如果一旦出现调不通的情况,长连接在超时的时间内还会一直保持着连接,而且还会复用上一次错误的连接信息。因此我们才会后续一直是400的情况,到我们重启之后,长连接全部重置,又恢复如初。
- 解决
所以解决这个问题只要在初始化HttpComponentsClientHttpRequestFactory的时候,传入自定义的HttpClient来实例HttpComponentsClientHttpRequestFactory,这样他就不会默认使用HttpClient的长连接,问题即可解决!
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
同时记得配置HttpClient最大连接数以及同路由并发数,防止高并发的时候RestTemplate的性能!
// 开始设置连接池
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
// 最大连接数
poolingHttpClientConnectionManager.setMaxTotal(maxTotal);
// 同路由并发数
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxPerRoute);、
- 总结
当编码的时候,一定要思考详细,注意细节,要多看源码!不要想当然的直接引用公共的方法或类,当使用的时候应该看看源码,了解他的原理,是怎么运行的,必要的配置是否配齐!
同时加入详细全面的测试,若是详细的自测,这个问题也是会显露出来的!
今天记录下来这个问题,时刻勉励自己,细节必决定成败!