解決feign調(diào)用接口不穩(wěn)定的問題
我就廢話不多說了,大家還是直接看代碼吧~
Caused by: java.net.SocketException: Software caused connection abort: recv failed at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:170) at java.net.SocketInputStream.read(SocketInputStream.java:141) at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137) at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153) at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163) at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:167) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55) at feign.httpclient.ApacheHttpClient.execute(ApacheHttpClient.java:87) at org.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:92) at org.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer$1.doWithRetry(RetryableFeignLoadBalancer.java:77) at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:286) at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:163) at org.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:77) at org.springframework.cloud.netflix.feign.ribbon.RetryableFeignLoadBalancer.execute(RetryableFeignLoadBalancer.java:48) at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:109) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) at rx.Observable.unsafeSubscribe(Observable.java:10211) at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) at rx.Observable.unsafeSubscribe(Observable.java:10211) at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) at rx.Observable.unsafeSubscribe(Observable.java:10211) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) at rx.Subscriber.setProducer(Subscriber.java:209) at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.Observable.subscribe(Observable.java:10307) at rx.Observable.subscribe(Observable.java:10274) at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445) at rx.observables.BlockingObservable.single(BlockingObservable.java:342) at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:117) at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ... 117 common frames omitted
feign在調(diào)用時(shí),會(huì)有不穩(wěn)定的情況出現(xiàn),時(shí)而出現(xiàn)接口調(diào)不通。解決方案如下,復(fù)寫FeignRibbonClientAutoConfiguration中的HttpClient的配置。代碼如下:
import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.NoConnectionReuseStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.KeyManagementException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @Component public class FeignRibbonHttpClientPoolConfig { private static final int POOL_MAX_TOTAL = 3000; private static final int DEFAULT_MAX_PER_ROUTE = 500; //validateAfterInactivity 空閑永久連接檢查間隔,這個(gè)牽扯的還比較多 //官方推薦使用這個(gè)來檢查永久鏈接的可用性,而不推薦每次請(qǐng)求的時(shí)候才去檢查 private static final int VALIDATE_AFTER_INACTIVITY = 1000; @Bean(name = "httpClient", destroyMethod = "close") CloseableHttpClient httpClient() throws KeyManagementException { return buildCloseableHttpClient(); } /** * 構(gòu)建HttpClient連接池 * * @return * @throws KeyManagementException */ public CloseableHttpClient buildCloseableHttpClient() throws KeyManagementException { SSLContext sslcontext = SSLContexts.createDefault(); sslcontext.init(null, new TrustManager[]{new TrustAnyManager()}, null); //設(shè)置https客戶端信任萬能證書 SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE); //注冊(cè)請(qǐng)求方式,根據(jù)URL自動(dòng)請(qǐng)求 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", ssf) .build(); //創(chuàng)建Http連接池,單位時(shí)間內(nèi)釋放已使用過連接池中的連接 PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connectionManager.setMaxTotal(POOL_MAX_TOTAL); connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); connectionManager.setValidateAfterInactivity(VALIDATE_AFTER_INACTIVITY); return HttpClients.custom() .setConnectionManager(connectionManager) .setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE) .build(); } class TrustAnyManager implements X509TrustManager { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } } }
補(bǔ)充知識(shí):springcloud之FeignClient訪問微服務(wù)接口緩慢
昨天開發(fā)FeignClient,想調(diào)用微服務(wù)。邏輯是A服務(wù)調(diào)用B服務(wù)。AB在同一個(gè)局域網(wǎng)內(nèi)。
經(jīng)過反復(fù)測(cè)試,有一個(gè)訪問緩慢的現(xiàn)象,具體表現(xiàn)為:
程序啟動(dòng)第一次訪問初始化1.2秒左右,還可以理解。
但后面訪問還是要1.1秒左右(格式化到SSS毫秒打印日志監(jiān)控的)。
但如果連續(xù)訪問幾次,后面幾次又是幾十毫秒。過一會(huì)再訪問,或者換瀏覽器換post工具請(qǐng)求,又會(huì)1.2秒左右。
當(dāng)時(shí)就有點(diǎn)懵逼,這么成熟的工具不可能會(huì)這么慢吧,都是一個(gè)局域網(wǎng)。
排查了eureka注冊(cè)中心,發(fā)現(xiàn)B服務(wù)多注冊(cè)了一個(gè),IP地址是192開頭,經(jīng)過詢問,是一個(gè)同事的筆記本連接wifi,wifi自動(dòng)分配了192開頭的ip,筆記本是可以訪問注冊(cè)中心和其他服務(wù)的。但其他服務(wù)是訪問不了這臺(tái)筆記本的。
也就是說,B服務(wù)的一個(gè)注冊(cè)的網(wǎng)絡(luò)和其他服務(wù)是不通的。
但不知道為什么eureka卻認(rèn)為192ip注冊(cè)是一個(gè)正確的微服務(wù),而且一直是UP狀態(tài)。注冊(cè)中心的ip肯定是訪問不了筆記本192ip的。
手工訪問了一下192ip,不會(huì)直接提示404或網(wǎng)絡(luò)錯(cuò)誤,而是會(huì)加載一會(huì)。
這也許導(dǎo)致了FeignClient認(rèn)為192ip是一臺(tái)可用的機(jī)器。所以第一次請(qǐng)求的時(shí)候就去請(qǐng)求192ip,但沒返回,到了超時(shí)時(shí)間,再換B服務(wù)的其他地址,就導(dǎo)致了耗時(shí)。
讓同事把服務(wù)停了,再次調(diào)用服務(wù),速度就很快了。
總結(jié):個(gè)別機(jī)器IP不通,會(huì)導(dǎo)致FeignClient調(diào)用微服務(wù)緩慢。而且在eureka中心中是UP狀態(tài),沒有錯(cuò)誤提示。
需要注意網(wǎng)絡(luò)互通情況。
以上這篇解決feign調(diào)用接口不穩(wěn)定的問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot學(xué)習(xí)系列之MyBatis Plus整合封裝的實(shí)例詳解
MyBatis-Plus是一款MyBatis的增強(qiáng)工具(簡稱MP),為簡化開發(fā)、提高效率,這篇文章給大家介紹MyBatis Plus整合封裝的實(shí)例詳解,感興趣的朋友跟隨小編一起看看吧2020-08-08Java獲取Cookie里的指定值的實(shí)現(xiàn)方法
在Java中,我們經(jīng)常需要從HTTP請(qǐng)求中獲取Cookie,并從中提取特定的值,下面我們將介紹如何通過Java代碼獲取Cookie中的指定值,文章通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09詳解idea搭建springboot+mybatis框架的教程
這篇文章主要介紹了詳解idea搭建springboot+mybatis框架的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11Java 使用多線程調(diào)用類的靜態(tài)方法的示例
這篇文章主要介紹了Java 使用多線程調(diào)用類的靜態(tài)方法的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-10-10通過FeignClient如何獲取文件流steam?is?close問題
這篇文章主要介紹了通過FeignClient如何獲取文件流steam?is?close問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06