聊聊openfeign的超时和重试

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 聊聊openfeign的超时和重试

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")
    @ResponseBody
    public 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覆盖。ribbon请求连接时间和超时时间,默认为1秒?请求连接时间和超时时间,默认为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.FeignAsEurekaClient#feignReadTimeout().execution.isolation.thread.timeoutInMilliseconds=15000

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

ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=11000

这里我必须说明一下,如果配置了feign的超时时间,并且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

注意,这里feign和ribbon的超时时间对上面这个配置都是不影响的


重试配置


如果不配置,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() {
  @Override
  public void continueOrPropagate(RetryableException e) {
    throw e;
  }
  @Override
  public Retryer clone() {
    return this;
  }
};

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

@Configuration
public class FeignConfigure {
    @Bean
    public Retryer feignRetryer(){
        // period=100 发起当前请求的时间间隔,单位毫秒
        // maxPeriod=1000 发起当前请求的最大时间间隔,单位毫秒
        // maxAttempts=2 重试次数是1,因为包括第一次,所以我们如果想要重试2次,就需要设置为3
        Retryer 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.ConnectTimeout=2000
ribbon.ReadTimeout=5000

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

2020-11-10 19: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 19: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 19:34:42,664 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> END HTTP (0-byte body)
2020-11-10 19: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 19:34:43,002 [hystrix-springboot-mybatis-1] [INFO] com.netflix.util.concurrent.ShutdownEnabledTimer - Shutdown hook installed for: NFLoadBalancer-PingTimer-springboot-mybatis
2020-11-10 19: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 19:34:43,011 [hystrix-springboot-mybatis-1] [INFO] com.netflix.loadbalancer.DynamicServerListLoadBalancer - Using serverListUpdater PollingServerListUpdater
2020-11-10 19: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 19: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 19: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 19:34:53,266 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- ERROR SocketTimeoutException: Read timed out (10600ms)
2020-11-10 19:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] java.net.SocketTimeoutException: Read timed out
  at 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 19:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- END ERROR
2020-11-10 19:34:53,267 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> RETRYING
2020-11-10 19: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 19:34:53,268 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] ---> END HTTP (0-byte body)
2020-11-10 19: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 19: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 19: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 19:34:58,274 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] <--- ERROR InterruptedIOException: thread interrupted (5006ms)
2020-11-10 19:34:58,275 [hystrix-springboot-mybatis-1] [DEBUG] boot.feign.FeignAsEurekaClient - [FeignAsEurekaClient#feignReadTimeout] java.io.InterruptedIOException: thread interrupted
  at 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客户端,重试功能不能作用。

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
4月前
|
负载均衡
OpenFeign重试组件Retryer原理
该文章主要讲解了OpenFeign中的重试组件Retryer的工作原理及其实现细节。
OpenFeign重试组件Retryer原理
|
4月前
|
负载均衡 Java Spring
Ribbon的超时配置会覆盖OpenFeign的超时配置吗
该文章详细分析了OpenFeign与Ribbon之间的超时配置关系,解释了Ribbon如何覆盖OpenFeign的默认超时配置,并探讨了OpenFeign超时配置的动态修改方案。
|
负载均衡 监控 Java
@SentinelResource和openFeign+sentinel 对远程调用熔断降级加规则持久化的具体实现
自定义全局限流处理类openFeign+sentinel 对远程调用熔断降级
173 0
Ribbon、Feign、Hystrix超时&重试&熔断问题
在使用Ribbon、Feign、Hystrix组合时,因为配置的问题出现以下现象,让我的大脑CPU烧的不行不行(拿我老家话说就是“脑子ran滴奥”)
188 0
|
消息中间件 Java
Springboot与RabbitMQ消息超时时间、队列消息超时时间
Springboot与RabbitMQ消息超时时间、队列消息超时时间
387 0
|
安全 Java
Hystrix超时机制为服务接口调用超时提供安全保护
Hystrix超时机制为服务接口调用超时提供安全保护
117 1
|
Java 数据处理 Spring
Spring Cloud OpenFeign 超时与重试
今天给大家分享的是 `feign` 的超时与重试配置。
872 0
Spring Cloud OpenFeign 超时与重试
|
Java Maven Spring
spring-retry实现方法请求重试
spring-retry实现方法请求重试
85 0
OpenFeign超时控制和日志打印功能
OpenFeign默认等待1秒钟,超过后报错 现在假设8001端口有一个请求复杂的业务,需要的时间比较长。
OpenFeign超时控制和日志打印功能
Feign超过失败重试后不知道怎么告警?
今天同事问我,使用Feign进行Http请求,当出现网络问题进行重试,假如超过了重试次数后想要发起一个告警要怎么做?
Feign超过失败重试后不知道怎么告警?