• 前言

就在昨天线上的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,可以看到源码是:

记录RestTemplate一个自己挖的坑-LMLPHP

记录RestTemplate一个自己挖的坑-LMLPHP

记录RestTemplate一个自己挖的坑-LMLPHP

由图可知HttpComponentsClientHttpRequestFactory默认用的是HttpClient,然后他的一个构建工厂HttpClientBuilder有一个属性是systemProperties。再看下面的源码:

记录RestTemplate一个自己挖的坑-LMLPHP

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);、
  • 总结

当编码的时候,一定要思考详细,注意细节,要多看源码!不要想当然的直接引用公共的方法或类,当使用的时候应该看看源码,了解他的原理,是怎么运行的,必要的配置是否配齐!

同时加入详细全面的测试,若是详细的自测,这个问题也是会显露出来的!

今天记录下来这个问题,时刻勉励自己,细节必决定成败!

03-16 01:48