解决feign调用接口不稳定的问题
我就废话不多说了,大家还是直接看代码吧~
Causedby:java.net.SocketException:Softwarecausedconnectionabort:recvfailed atjava.net.SocketInputStream.socketRead0(NativeMethod) atjava.net.SocketInputStream.socketRead(SocketInputStream.java:116) atjava.net.SocketInputStream.read(SocketInputStream.java:170) atjava.net.SocketInputStream.read(SocketInputStream.java:141) atorg.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137) atorg.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153) atorg.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282) atorg.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140) atorg.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) atorg.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) atorg.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163) atorg.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167) atorg.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) atorg.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) atorg.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271) atorg.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) atorg.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) atorg.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) atorg.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) atorg.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) atorg.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107) atorg.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55) atfeign.httpclient.ApacheHttpClient.execute(ApacheHttpClient.java:87) atorg.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:92) atorg.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:77) atorg.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:286) atorg.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:163) atorg.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:77) atorg.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:48) atcom.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:109) atcom.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) atcom.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) atrx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) atrx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) atrx.Observable.unsafeSubscribe(Observable.java:10211) atrx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) atrx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) atcom.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) atcom.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) atrx.Observable.unsafeSubscribe(Observable.java:10211) atrx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) atrx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) atrx.Observable.unsafeSubscribe(Observable.java:10211) atrx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) atrx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) atrx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) atrx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) atrx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) atrx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) atrx.Subscriber.setProducer(Subscriber.java:209) atrx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) atrx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) atrx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) atrx.Observable.subscribe(Observable.java:10307) atrx.Observable.subscribe(Observable.java:10274) atrx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445) atrx.observables.BlockingObservable.single(BlockingObservable.java:342) atcom.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:117) atorg.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) atfeign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ...117commonframesomitted
feign在调用时,会有不稳定的情况出现,时而出现接口调不通。解决方案如下,复写FeignRibbonClientAutoConfiguration中的HttpClient的配置。代码如下:
importorg.apache.http.config.Registry; importorg.apache.http.config.RegistryBuilder; importorg.apache.http.conn.socket.ConnectionSocketFactory; importorg.apache.http.conn.socket.PlainConnectionSocketFactory; importorg.apache.http.conn.ssl.NoopHostnameVerifier; importorg.apache.http.conn.ssl.SSLConnectionSocketFactory; importorg.apache.http.impl.NoConnectionReuseStrategy; importorg.apache.http.impl.client.CloseableHttpClient; importorg.apache.http.impl.client.HttpClients; importorg.apache.http.impl.conn.PoolingHttpClientConnectionManager; importorg.apache.http.ssl.SSLContexts; importorg.springframework.context.annotation.Bean; importorg.springframework.stereotype.Component; importjavax.net.ssl.SSLContext; importjavax.net.ssl.TrustManager; importjavax.net.ssl.X509TrustManager; importjava.security.KeyManagementException; importjava.security.cert.CertificateException; importjava.security.cert.X509Certificate; @Component publicclassFeignRibbonHttpClientPoolConfig{ privatestaticfinalintPOOL_MAX_TOTAL=3000; privatestaticfinalintDEFAULT_MAX_PER_ROUTE=500; //validateAfterInactivity空闲永久连接检查间隔,这个牵扯的还比较多 //官方推荐使用这个来检查永久链接的可用性,而不推荐每次请求的时候才去检查 privatestaticfinalintVALIDATE_AFTER_INACTIVITY=1000; @Bean(name="httpClient",destroyMethod="close") CloseableHttpClienthttpClient()throwsKeyManagementException{ returnbuildCloseableHttpClient(); } /** *构建HttpClient连接池 * *@return *@throwsKeyManagementException */ publicCloseableHttpClientbuildCloseableHttpClient()throwsKeyManagementException{ SSLContextsslcontext=SSLContexts.createDefault(); sslcontext.init(null,newTrustManager[]{newTrustAnyManager()},null);//设置https客户端信任万能证书 SSLConnectionSocketFactoryssf=newSSLConnectionSocketFactory(sslcontext,NoopHostnameVerifier.INSTANCE); //注册请求方式,根据URL自动请求 RegistrysocketFactoryRegistry=RegistryBuilder. create() .register("http",PlainConnectionSocketFactory.INSTANCE) .register("https",ssf) .build(); //创建Http连接池,单位时间内释放已使用过连接池中的连接 PoolingHttpClientConnectionManagerconnectionManager=newPoolingHttpClientConnectionManager(socketFactoryRegistry); connectionManager.setMaxTotal(POOL_MAX_TOTAL); connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); connectionManager.setValidateAfterInactivity(VALIDATE_AFTER_INACTIVITY); returnHttpClients.custom() .setConnectionManager(connectionManager) .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE) .build(); } classTrustAnyManagerimplementsX509TrustManager{ publicvoidcheckClientTrusted(X509Certificate[]chain, StringauthType)throwsCertificateException{ } publicvoidcheckServerTrusted(X509Certificate[]chain, StringauthType)throwsCertificateException{ } publicX509Certificate[]getAcceptedIssuers(){ returnnewX509Certificate[]{}; } } }
补充知识:springcloud之FeignClient访问微服务接口缓慢
昨天开发FeignClient,想调用微服务。逻辑是A服务调用B服务。AB在同一个局域网内。
经过反复测试,有一个访问缓慢的现象,具体表现为:
程序启动第一次访问初始化1.2秒左右,还可以理解。
但后面访问还是要1.1秒左右(格式化到SSS毫秒打印日志监控的)。
但如果连续访问几次,后面几次又是几十毫秒。过一会再访问,或者换浏览器换post工具请求,又会1.2秒左右。
当时就有点懵逼,这么成熟的工具不可能会这么慢吧,都是一个局域网。
排查了eureka注册中心,发现B服务多注册了一个,IP地址是192开头,经过询问,是一个同事的笔记本连接wifi,wifi自动分配了192开头的ip,笔记本是可以访问注册中心和其他服务的。但其他服务是访问不了这台笔记本的。
也就是说,B服务的一个注册的网络和其他服务是不通的。
但不知道为什么eureka却认为192ip注册是一个正确的微服务,而且一直是UP状态。注册中心的ip肯定是访问不了笔记本192ip的。
手工访问了一下192ip,不会直接提示404或网络错误,而是会加载一会。
这也许导致了FeignClient认为192ip是一台可用的机器。所以第一次请求的时候就去请求192ip,但没返回,到了超时时间,再换B服务的其他地址,就导致了耗时。
让同事把服务停了,再次调用服务,速度就很快了。
总结:个别机器IP不通,会导致FeignClient调用微服务缓慢。而且在eureka中心中是UP状态,没有错误提示。
需要注意网络互通情况。
以上这篇解决feign调用接口不稳定的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。