openfeign是一种声明式的http客户端,它可以方便地集成到springcloud,像调用本地方法一样使用http方式调用远程服务。今天我们来聊一聊feign的超时和重试。

构建环境

注:本文使用的openfeign版本:2.1.0.RELEASE

在pom文件中增加下面配置:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.1.0.RELEASE</version>
</dependency>

openfeign默认使用java原生的URLConnection。这里我们要选择一个http的客户端,比如选择apache的,需要在application.properties文件中增加下面这个配置:

feign.httpclient.enabled=true

同时需要在pom文件中引入下面这个jar包:

<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId><version>9.3.1</version>
</dependency>

我们也可以选择okhttp的,这时需要在application.properties文件中增加下面这个配置:

feign.okhttp.enabled=true

同时需要在pom文件中进入okhttp的jar包:

<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId><version>10.2.0</version>
</dependency>

在我本地的实验中,有一个服务叫springboot-mybatis,eureka地址是localhost:8889,在application.properties文件中加入下面配置:

eureka.instance.hostname=localhost
eureka.instance.prefer-ip-address=true
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:8889/eureka/

boot启动类加上下面这个注解:

@EnableFeignClients

这样就初步实现了一个openfeign的配置,我在服务端工程(springboot-mybatis)中增加了一个方法,让客户端来调用,代码如下:

@Controller
@RequestMapping("/feign")
public class FeignTestController {@RequestMapping("/feignReadTimeout")@ResponseBodypublic String getEmployeebyName() throws InterruptedException {//这里配置10s的超时时间,给后面的实验用Thread.currentThread().sleep(10000);return "success";}
}

在feign客户端的调用代码如下:

@FeignClient("springboot-mybatis")
public interface FeignAsEurekaClient {@GetMapping("/feign/feignReadTimeout")String feignReadTimeout();
}

超时配置

注:下面的实验使用的是okhttp来进行的。

上面实现了一个简单的feign使用demo,不过feign的使用还有很多需要注意的地方,这里我们来聊一聊超时。先看第一种情况,feign客户端和服务端都注册在一个eureka的情况。

 1.不配置超时时间,默认"读超时60s"

上面的demo我们没有设置超时时间,所以虽然服务端响应延迟10s,请求还是能成功的。

但是上面的"读超时60s"我加了引号,为什么呢?在feign.Request里面有一个内部类,如果不配置超时,外部会调用下面这个构造函数,连接超时10s,读超时60s

public Options() {this(10 * 1000, 60 * 1000);
}

如果我们没有配置feign超时时间,上面的时间也会被ribbon覆盖?请求连接时间和超时时间,默认为1秒,在RibbonClientConfiguration类定义,被覆盖后也是会读超时的。

覆盖超时时间设置的代码在FeignLoadBalancer,代码如下:

public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)throws IOException {Request.Options options;if (configOverride != null) {RibbonProperties override = RibbonProperties.from(configOverride);options = new Request.Options(override.connectTimeout(this.connectTimeout),override.readTimeout(this.readTimeout));}else {options = new Request.Options(this.connectTimeout, this.readTimeout);}Response response = request.client().execute(request.toRequest(), options);return new RibbonResponse(request.getUri(), response);
}

所以我们加入下面的配置,把ribbon的读超时时间调大,也是可以解决读超时问题的:

ribbon.okhttp.enabled=true
#ribbon.ConnectTimeout=2000
#请求处理的超时时间
ribbon.ReadTimeout=10000

但ribbon是一个做负载均衡的,我们还是给feign定义超时时间比较好。因为feign配置了超时时间后,会最后赋值给Options的超时时间。在FeignClientFactoryBean类的configureUsingProperties方法。

if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {builder.options(new Request.Options(config.getConnectTimeout(), config.getReadTimeout()));
}

2.配置一个默认超时时间

feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=5000

这里我配置了连接超时是2s,读取超时是5s,这样,上面demo中的请求就失败了,要想成功,readTimeout不能低于10000。

3.为单个服务设置超时时间

如果我们有一个接口超时时间很长,要全局都设置一个这么长的超时时间吗?这样会有问题,一个平时响应很快的接口,如果服务端出故障了,我们应该让它fail-fast。这样我们就需要对慢的接口或服务单独设置超时时间。

对某一个服务设置单独的超时时间,配置如下:

#对单个服务设置超时,会覆盖默认的超时
feign.client.config.springboot-mybatis.connectTimeout=2000
feign.client.config.springboot-mybatis.readTimeout=11000

4.为单个接口设置超时时间

还是上面的问题,一个服务有多个接口,只有一个超级慢,那对整个服务的所有接口设置一个超时时间也会影响其他接口的fail-fast,我们需要对单个接口设置超时时间,就得配合hystrix来配置了,配置如下:

#开启熔断
#feign.hystrix.enabled=true#开启超时熔断,默认为true,如果为false,则熔断机制只在服务不可用时开启,这个配置不加,使用默认配置
#hystrix.command.default.execution.timeout.enabled=false#如果上面一个配置是true,设置超时熔断时间,因为openfeign中的熔断时间默认是1s,太短了,我们必须手工设置一个
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=15000
#下面的配置为单个接口设置超时时间
#xxx:要设置的某个FeignClient的类名
#yyy:方法名
#zzz:参数,如果是基础类型,就直接填基础类型:String/int;如果是某个对象,就直接填对象的类名
#hystrix.command.xxx#yyy(zzz).execution.isolation.thread.timeoutInMilliseconds=1000
#hystrix.command.FeignAsHttpCient#feignReadTimeout().execution.isolation.thread.timeoutInMilliseconds=23000

这里必须注意一下,ribbon的读超时时间也不能小于接口的返回时间,不然回报ribbon超时,所以ribbon配置如下:

ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=11000

这里我必须说明一下,如果配置了feign的超时时间,并且feign的读超时不够,熔断的超时时间是不起作用的。坑爹啊。原因是什么呢?有待研究。

原因:这里hystrix的时间其实并没有起作用,起作用的其实还是feign的超时时间

那不是说openfeign如果给单个服务设置了超时时间,或设置了默认超时时间,就不能给单个响应慢的接口设置超时时间了吗?

下面我们看第二种情况,使用feign作为http客户端来调用外部的服务情况。这种情况的客户端我也给出一个,服务的接口还是刚刚那个:

@FeignClient(name = "feign", url = "http://localhost:8083")
public interface FeignAsHttpCient {@GetMapping("/feign/feignReadTimeout")String feignReadTimeout();
}

这里我们需要在application.properties文件中增加下面这个配置就可以了:

hystrix.command.FeignAsHttpCient#feignReadTimeout().execution.isolation.thread.timeoutInMilliseconds=11000

注意:这里hystrix的时间其实并没有起作用,起作用的其实还是feign的超时时间

那对单个接口怎么设置超时时间呢,我给出一个参考,如下:

public class RestTemplateConfiguration {@Beanpublic OkHttp3ClientHttpRequestFactory okHttp3RequestFactory(){OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory();//注意:这里配置了超时时间,就不受ribbon超时时间的影响了requestFactory.setConnectTimeout(2000);requestFactory.setReadTimeout(15000);return requestFactory;}@Bean@LoadBalancedpublic RestTemplate restTemplate(OkHttp3ClientHttpRequestFactory okHttp3RequestFactory){return new RestTemplate(okHttp3RequestFactory);}
}

如果作为eureka客户端,需要加@LoadBalanced的注解,发送请求代码如下,springboot-mybatis是请求的服务名:

String response = restTemplate.getForObject("http://springboot-mybatis/feign/feignReadTimeout", String.class);

如果作为普通http客户端,不能加@LoadBalanced的注解,发送请求代码如下:

String response = restTemplate.getForObject("http://localhost:8083/feign/feignReadTimeout", String.class);

重试配置

如果不配置,openfeign默认是不重试的,看FeignClientsConfiguration中的代码:

@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {return Retryer.NEVER_RETRY;
}

再看一下Retryer中的NEVER_RETRY定义:

/*** Implementation that never retries request. It propagates the RetryableException.*/
Retryer NEVER_RETRY = new Retryer() {@Overridepublic void continueOrPropagate(RetryableException e) {throw e;}@Overridepublic Retryer clone() {return this;}
};

下面我给出一个重试的配置:

@Configuration
public class FeignConfigure {@Beanpublic Retryer feignRetryer(){// period=100 发起当前请求的时间间隔,单位毫秒// maxPeriod=1000 发起当前请求的最大时间间隔,单位毫秒// maxAttempts=2 重试次数是1,因为包括第一次,所以我们如果想要重试2次,就需要设置为3Retryer retryer = new Retryer.Default(100, 1000, 2);return retryer;}
}

注意:

hystrix是在ribbon外面,所以hystrix的超时时间不能小于ribbon的(ConnectTimeout + ReadTimeout) * maxAttempts
这样才能保证在Ribbon里的请求还没结束时,Hystrix的熔断时间不会超时

比如下面这个配置:

#feign.client.config.springboot-mybatis.connectTimeout=2000
#feign.client.config.springboot-mybatis.readTimeout=5000
hystrix.command.FeignAsEurekaClient#feignReadTimeout().execution.isolation.thread.timeoutInMilliseconds=15000
ribbon.ReadTimeout=5000

这个时候再执行测试用例FeignAsEurekaClient.feignReadTimeout,打印日志如下,可以看到有2次请求,第2次是重试:

2020-11-10 09:34:42,011 [main] [INFO] org.springframework.test.context.transaction.TransactionContext - Began transaction (1) for test context [DefaultTestContext@587e5365 testClass = TestFeignAsEurekaClient, testInstance = boot.service.TestFeignAsEurekaClient@26b3fd41, testMethod = testFeignReadTimeOut@TestFeignAsEurekaClient, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@22fcf7ab testClass = TestFeignAsEurekaClient, locations = '{}', classes = '{class boot.Application, class boot.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@f4168b8, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@74294adb, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@11c20519, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@25359ed8], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@56f3f9da]; rollback [true]
2020-11-10 09:34:42,664 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> GET http://springboot-mybatis/feign/feignReadTimeout HTTP/1.1
2020-11-10 09:34:42,664 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> END HTTP (0-byte body)
2020-11-10 09:34:42,975 [hystrix-springboot-mybatis-1] [INFO] com.netflix.config.ChainedDynamicProperty - Flipping property: springboot-mybatis.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-11-10 09:34:43,002 [hystrix-springboot-mybatis-1] [INFO] com.netflix.util.concurrent.ShutdownEnabledTimer - Shutdown hook installed for: NFLoadBalancer-PingTimer-springboot-mybatis
2020-11-10 09:34:43,003 [hystrix-springboot-mybatis-1] [INFO] com.netflix.loadbalancer.BaseLoadBalancer - Client: springboot-mybatis instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=springboot-mybatis,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2020-11-10 09:34:43,011 [hystrix-springboot-mybatis-1] [INFO] com.netflix.loadbalancer.DynamicServerListLoadBalancer - Using serverListUpdater PollingServerListUpdater
2020-11-10 09:34:43,066 [hystrix-springboot-mybatis-1] [INFO] com.netflix.config.ChainedDynamicProperty - Flipping property: springboot-mybatis.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-11-10 09:34:43,071 [hystrix-springboot-mybatis-1] [INFO] com.netflix.loadbalancer.DynamicServerListLoadBalancer - DynamicServerListLoadBalancer for client springboot-mybatis initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=springboot-mybatis,current list of Servers=[10.192.84.93:8083],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;   Instance count:1;   Active connections count: 0;    Circuit breaker tripped count: 0;   Active connections per server: 0.0;]
},Server stats: [[Server:10.192.84.93:8083; Zone:defaultZone;   Total Requests:0;   Successive connection failure:0;    Total blackout seconds:0;   Last connection made:Thu Jan 01 08:00:00 CST 1970;  First connection made: Thu Jan 01 08:00:00 CST 1970;    Active Connections:0;   total failure count in last (1000) msecs:0; average resp time:0.0;  90 percentile resp time:0.0;    95 percentile resp time:0.0;    min resp time:0.0;  max resp time:0.0;  stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@77f618f
2020-11-10 09:34:44,028 [PollingServerListUpdater-0] [INFO] com.netflix.config.ChainedDynamicProperty - Flipping property: springboot-mybatis.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2020-11-10 09:34:53,266 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- ERROR SocketTimeoutException: Read timed out (10600ms)
2020-11-10 09:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] java.net.SocketTimeoutException: Read timed outat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)at java.net.SocketInputStream.read(SocketInputStream.java:171)at java.net.SocketInputStream.read(SocketInputStream.java:141)at okio.Okio$2.read(Okio.java:139)at okio.AsyncTimeout$2.read(AsyncTimeout.java:237)at okio.RealBufferedSource.indexOf(RealBufferedSource.java:345)at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:217)at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:211)at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:189)at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:75)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)at okhttp3.RealCall.execute(RealCall.java:69)at feign.okhttp.OkHttpClient.execute(OkHttpClient.java:167)at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:90)at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:56)at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:104)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:10151)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:10151)at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)at rx.Observable.unsafeSubscribe(Observable.java:10151)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:10247)at rx.Observable.subscribe(Observable.java:10214)at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:444)at rx.observables.BlockingObservable.single(BlockingObservable.java:341)at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112)at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:65)at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:108)at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:106)at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302)at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)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.unsafeSubscribe(Observable.java:10151)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51)at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35)at rx.Observable.unsafeSubscribe(Observable.java:10151)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)at rx.Observable.unsafeSubscribe(Observable.java:10151)at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47)at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69)at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)2020-11-10 09:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- END ERROR
2020-11-10 09:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> RETRYING
2020-11-10 09:34:53,268 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> GET http://springboot-mybatis/feign/feignReadTimeout HTTP/1.1
2020-11-10 09:34:53,268 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> END HTTP (0-byte body)2020-11-10 09:34:58,270 [hystrix-springboot-mybatis-1] [WARN] com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
2020-11-10 09:34:58,271 [hystrix-springboot-mybatis-1] [INFO] com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2020-11-10 09:34:58,272 [hystrix-springboot-mybatis-1] [INFO] com.netflix.config.DynamicPropertyFactory - DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@5f87f8d3
2020-11-10 09:34:58,274 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- ERROR InterruptedIOException: thread interrupted (5006ms)
2020-11-10 09:34:58,275 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] java.io.InterruptedIOException: thread interruptedat okio.Timeout.throwIfReached(Timeout.java:145)at okio.Okio$1.write(Okio.java:76)at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)at okio.RealBufferedSink.flush(RealBufferedSink.java:216)at okhttp3.internal.http1.Http1Codec.finishRequest(Http1Codec.java:166)at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:72)at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)

而如果把配置改成下面的配置,就只有一次请求了,没有进行重试:

#feign.client.config.springboot-mybatis.connectTimeout=2000
#feign.client.config.springboot-mybatis.readTimeout=5000
hystrix.command.FeignAsEurekaClient#feignReadTimeout().execution.isolation.thread.timeoutInMilliseconds=8000
ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=5000

这里也要注意:如果使用feign作为普通http客户端(不是eureka客户端),是没有重试功能的。

总结

使用openfeign作为http客户端使用起来非常方便,不过也要注意一些复杂场景,比如作为eureka客户端对单个接口设置超时时间,配置比较复杂,需要借助熔断,而且跟整体服务的超时不兼容。
使用openfeign作为普通http客户端,重试功能不能作用。


欢迎关注个人公众号

聊聊openfeign的超时和重试相关推荐

  1. 超时,重试,熔断,限流

    1 写在前面 1.1 名词解释 consumer表示服务调用方 provider标示服务提供方,dubbo里面一般就这么讲. 下面的A调用B服务,一般是泛指调用B服务里面的一个接口. 1.2 拓扑图 ...

  2. envoy重试_具有Envoy代理的微服务模式,第二部分:超时和重试

    envoy重试 该博客是系列文章的一部分,该系列文章更深入地介绍了Envoy Proxy和Istio.io ,以及它如何实现一种更优雅的连接和管理微服务的方式. 跟随我@christianposta ...

  3. 使用Envoy代理的微服务模式,第二部分:超时和重试

    该博客是系列文章的一部分,该系列文章更深入地介绍了Envoy Proxy和Istio.io ,以及它如何实现更优雅的连接和管理微服务的方式. 跟随我@christianposta ,紧跟这些博客文章的 ...

  4. python requests 代理超时_python requests 超时与重试

    一 源起: requests模块作为python爬虫方向的基础模块实际上在日常实际工作中也会涉及到,比如用requests向对方接口url发送POST请求进行推送数据,使用GET请求拉取数据. 但是这 ...

  5. HttpInterceptor 拦截器 - 网络请求超时与重试的简单实现

    ... 拦截器在Angular项目中其实有着十分重要的地位,拦截器可以统一对 HTTP 请求进行拦截处理,我们可以在每个请求体或者响应后对应的流添加一系列动作或者处理数据,再返回给使用者调用. 每个 ...

  6. CSDN发文章显示超时请重试

    csdn发文章显示超时请重试 解决办法 1.切换网络 尝试关闭wifi,关闭数据都还是没有解决 2.保存重发 用csdn手机app发文章没有保存的选择,自己退出csdn,打开进去,软件自动将其保存为草 ...

  7. Istio超时与重试

    一.理解超时与重试 超时的原理是,如果程序请求长时间无法返回结果,则需要设置超时机制,超过设置的时间则返回错误的信息:这样做既可以节约等待时消耗的资源,也可以避免由于级联错误引起的一系列问题.设置超时 ...

  8. qq服务器运行失败,QQ连接服务器超时,请重试,错误码0x00000001解决方法分享

    QQ连接服务器超时,请重试!错误码0x00000001的解决方法 0X00000001解决方法:运行中键入cmd,打开后键入 复制代码代码如下:for %1 in (%windir%\system32 ...

  9. qq发送消息连接服务器超时,QQ连接服务器超时,请重试,错误码0x00000001解决方法...

    QQ连接服务器超时,请重试!错误码0x00000001的解决方法 0X00000001解决方法:运行中键入cmd,打开后键入 for %1 in (%windir%\system32\*.dll) d ...

最新文章

  1. Blend4精选案例图解教程(三):一键拖拽
  2. UML第一次作业:UML用例图绘制
  3. Python 强大的信号库 blinker 入门教程
  4. mybatis sql中有中文处理
  5. 涨姿势,图文带你了解 8 大排序算法
  6. html中列表、表格、合并单元格
  7. 海云捷迅让OpenStack从项目实施转为服务交付
  8. JavaIO流实现文件传输
  9. 3. 无线体内纳米网:图文概述
  10. 首届百度Apollo生态大会为什么选择长沙?
  11. 采集网易云上面的MV保存方法
  12. kindle书摘-围城-相爱勿相伤
  13. 在百度Create 2021大会聆听李彦宏,王海峰“论道”AI
  14. 想再考一个教师资格证,相同的科目需要重考笔试吗?
  15. docker导入镜像报错:open /var/lib/docker/tmp/docker-import-970689518/bin/json: no such file or
  16. xp计算机硬盘东西不显示,WinXP系统电脑找不到硬盘怎么办 WinXP系统找不到硬盘的原因及解决方法...
  17. 小型数控钻铣床C31
  18. 串口监听工具listen_串口命令解析
  19. cmd(命令行)操作或连接mysql数据库,以及创建数据库与表
  20. win7 开启无线网

热门文章

  1. 记录安装使用联邦机器学习FATE框架
  2. 百度研究院:2020年10大人工智能科技趋势
  3. (附源码)ssm微课堂知识考核系统 毕业设计 141147
  4. android对接易支付,EasyPay(易支付),两分钟集成三种Android支付方式
  5. 【halcon-案例】刀痕崩边检测
  6. java圣经_Java设计模式圣经连载(01)-简单工厂模式[转载]
  7. TensorFlow的几个问题
  8. 使用share SDK实现人人网授权登录分享(1.x版本)
  9. kali安装amritage
  10. vant list组件使用的坑