Spring Cloud Feign客户端与Hystrix断路器的超时默认值为2秒。

huangapple go评论66阅读模式
英文:

Spring Cloud Feign client with Hystrix circuit-breaker timeout defaults in 2 seconds

问题

以下是您要翻译的内容:

通过GitHub上的项目可重现:spring-cloud-feign-hystrix-timeout-problem


我正在使用Spring Boot 2.3.1.RELEASE与Spring Cloud Hoxton.SR6。具体来说,使用Feign客户端和Hystrix,而不使用Zuul和Eureka来获取REST响应。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Hoxton.SR6</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

然后,我在Spring Boot 2.3.1.RELEASESpring Cloud Hoxton.SR6的基础上使用以下依赖项:

  • org.springframework.boot:spring-boot-starter
  • org.springframework.boot:spring-boot-starter-web
  • org.springframework.cloud:spring-cloud-starter-openfeign
  • org.springframework.cloud:spring-cloud-starter-netflix-hystrix

我启用了@EnableFeignClients@EnableCircuitBreaker,并使用@FeignClient,具有一个简单的回退来记录并重新抛出异常:

@FeignClient(name = "my-feign", url = "${feign.url}", fallbackFactory = MyFallbackFactory.class)
public interface MyFeignClient {

    @PostMapping(value = "/api/dto")
    postDto(@RequestBody Dto dto);
}

使用以下application.yml,超时约为1秒,因为Hystrix默认为相同的值:

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

> 11:52:05.493 INFO 10200 --- [nio-8060-exec-2] com.mycompany.rest.MyController : Calling REST right now!
>
> 11:52:06.538 ERROR 24044 --- [nio-8060-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: MyFeignClient#postDto(Dto) timed-out and fallback failed.] with root cause


我尝试了什么?

只要我添加以下行以增加超时时间到60秒,超时时间就有效地增加到2秒

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000

> 11:53:33.590 INFO 16052 --- [nio-8060-exec-2] com.mycompany.rest.MyController : Calling REST right now!
>
> 11:53:35.614 ERROR 16052 --- [nio-8060-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: MyFeignClient#postDto(Dto) failed and fallback failed.] with root cause

只要增加了Hystrix的读取/连接超时时间,调用就会在2秒内陷入回退状态。但是,根据我在feign.client.config.default...中声明的超时时间,我希望实现5秒。我感觉我错过了另一个配置。

问:如何增加超时时间?


编辑:

英文:

Reproducible through a project on GitHub: spring-cloud-feign-hystrix-timeout-problem


I am using Spring Boot 2.3.1.RELEASE with Spring Cloud Hoxton.SR6. Namely Feign client and Hystrix without Zuul and Eureka to fetch REST responses.

&lt;dependency&gt;
   &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
   &lt;artifactId&gt;spring-cloud-dependencies&lt;/artifactId&gt;
   &lt;version&gt;Hoxton.SR6&lt;/version&gt;
   &lt;type&gt;pom&lt;/type&gt;
   &lt;scope&gt;import&lt;/scope&gt;
&lt;/dependency&gt;

Then I use use the following dependencies on top of Spring Boot 2.3.1.RELEASE and Spring Cloud Hoxton.SR6:

  • org.springframework.boot:spring-boot-starter
  • org.springframework.boot:spring-boot-starter-web
  • org.springframework.cloud:spring-cloud-starter-openfeign
  • org.springframework.cloud:spring-cloud-starter-netflix-hystrix

I enable @EnableFeignClients and @EnableCircuitBreaker and use a @FeignClient with a simple fallback to log and rethrow an exception:

@FeignClient(name=&quot;my-feign&quot;, url = &quot;${feign.url}&quot;, fallbackFactory = MyFallbackFactory.class) {
public interface MyFeignClient {

    @PostMapping(value = &quot;/api/dto&quot;)
    postDto(@RequestBody Dto dto);
}

With the following application.yml the timeout is around 1 second because Hystrix defaults to the very same value:

feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

> 11:52:05.493 INFO 10200 --- [nio-8060-exec-2] com.mycompany.rest.MyController : Calling REST right now!
>
> 11:52:06.538 ERROR 24044 --- [nio-8060-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: MyFeignClient#postDto(Dto) timed-out and fallback failed.] with root cause


What I tried?

As long as I add the following lines to increase the timeouts to 60 seconds, the timeout become effectively around 2 seconds:

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000

> 11:53:33.590 INFO 16052 --- [nio-8060-exec-2] com.mycompany.rest.MyController : Calling REST right now!
>
> 11:53:35.614 ERROR 16052 --- [nio-8060-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: MyFeignClient#postDto(Dto) failed and fallback failed.] with root cause

The call falls into fallback right in 2 seconds as long as the Hystrix read/connect timeouts have been increased. However I expect to achieve 5 seconds as long as I declared it in feign.client.config.default... timeouts. I feel I am missing another configuration.

Q: How to increase the timeout?


Edit:

答案1

得分: 4

你的配置是正确的,你描述的行为是预期的。问题在于,当出现Connection refused异常时,并没有在你配置的超时时间——10秒后抛出。相反,在Java的内部套接字实现发现服务器主机不可达后立即抛出该异常。在最简单的情况下,你所调用的服务器可能没有启动。

至于为什么在你设置了Hystrix超时后会有第二次增加,你可以调试Hystrix的调用堆栈,找出HystrixRuntimeException的抛出顺序不同。

在你自定义的Hystrix超时之前,Hystrix的默认超时时间为1秒,这意味着一旦执行时间超过1秒,无论请求成功还是失败,都会抛出这个运行时异常。所以在你的情况下,Connection refused很可能会在HystrixTimeoutException之后发生。当你将超时时间设置得比Feign客户端的超时时间长时,HystrixTimeoutException只会在Feign异常(由于"Connection refused")抛出之后才被创建,因此会有延迟。

为了模拟超时,你可以在服务器端强制超时,比如使用Thread.sleep(6000)来延迟服务器端的执行,或者在调试器中设置断点。

英文:

Your configuration is correct and what you are describing is expected behavior. The issue here is that exception with Connection refused isn't thrown after your configured timeout -- 10 seconds. Instead, it is thrown immediately after Java's internal socket implementation finds that server host is not reachable. In simplest case, the server you are calling isn't up and running.

As to why there is a second increase after you set the hystrix timeout, you can debug hystrix's call stack to find out that HystrixRuntimeException isn't being thrown in the same order.

Before your custom hystrix timeout, hystrix had a default timeout of 1 second, which means this runtime exception is always thrown once one second since execution has lapsed, regardless whether the request succeeds or fails. So in your case, Connection refused could very likely happen after HystrixTimeoutException. After you set the timeout be to longer than that of feign client, HystrixTimeoutException only gets created after a feign exception is thrown (due to "Connection refused"), hence the delay.

// &#39;cause&#39; should be different due to timing
public HystrixRuntimeException(... Exception cause, Throwable fallbackException)

To simulate the timeout, I'd say you could force a timeout on the server, such as Thread.sleep(6000) to halt the execution on server side, or simply do a breakpoint while on debugger.

答案2

得分: 2

你可以尝试的一件事是将Hystrix超时的配置属性定义在一行中(我知道这应该等同于你在YAML文件中提出的嵌套定义,但有时我遇到只能以这种方式加载的属性)。正如你可以在他们的测试中看到的,这是Spring Cloud自身配置Hystrix超时的方式:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000

此外,尽管你指出你没有使用Zuul或Eureka,请验证一下是否以某种方式使用了Ribbon,因为Hystrix和Ribbon的超时之间存在一些依赖关系(请参见https://github.com/Netflix/Hystrix/issues/1778和https://github.com/spring-cloud/spring-cloud-netflix/issues/1324)。

如果是这种情况,你必须配置两个库的超时:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
ribbon:
  ConnectTimeout: 5000
  ReadTimeout: 5000
英文:

One thing you can try is to define the configuration property of the Hystrix timeout in a single line (I know that it should be equivalent to the nested definition you proposed in your YAML file, but sometimes I came across properties that only were loaded in this way). As you can see in their tests, this is the way Spring Cloud itself configures Hystrix timeout:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000

Also, although you indicated that you are not using Zuul or Eureka, please, verify if you are using Ribbon in any way, there is some dependencies (see https://github.com/Netflix/Hystrix/issues/1778 and https://github.com/spring-cloud/spring-cloud-netflix/issues/1324) between the Hystrix and Ribbon timeouts.

If it is the case, you must configure the timeouts of both libraries:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
ribbon:
  ConnectTimeout: 5000
  ReadTimeout: 5000

huangapple
  • 本文由 发表于 2020年8月7日 18:00:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63299493.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定