Spring 带有 Hystrix 断路器超时的 Cloud Feign 客户端默认为 2 秒

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

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


我正在使用 Spring 引导 2.3.1.RELEASE 和 Spring 云 Hoxton.SR6。即没有 Zuul 和 Eureka 的 Feign 客户端和 Hystrix 来获取 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 之上使用以下依赖项:

我启用 @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 read/connect 超时增加,调用就会在 2 秒 后进入后备状态。但是,只要我在 feign.client.config.default... 超时中声明它,我希望达到 5 秒 。我觉得我缺少另一个配置。

问:如何增加超时时间?


编辑:

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

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

此外,虽然您表示您没有使用 Zuul 或 Eureka,但请验证您是否以任何方式使用 Ribbon,Hystrix 和 Ribbon 超时之间存在一些依赖关系(请参阅 https://github.com/Netflix/Hystrix/issues/1778 and https://github.com/spring-cloud/spring-cloud-netflix/issues/1324)。

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

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

您的配置是正确的,您所描述的是预期的行为。这里的问题是 Connection refused 的异常不会在您配置的超时后抛出 - 10 秒。相反,它会在 Java 的内部套接字实现发现服务器主机不可访问后立即抛出。在最简单的情况下,您调用的服务器未启动并且 运行.

至于为什么设置了hystrix timeout后会第二次增加,可以debug hystrix的调用栈发现HystrixRuntimeException不是按顺序抛出的

在你自定义的hystrix超时之前,hystrix有一个默认的1秒超时,这意味着这个运行时异常总是在执行失效后一秒抛出一次,不管请求是成功还是失败。所以在你的情况下,Connection refused 很可能发生在 HystrixTimeoutException 之后。将超时设置为比假装客户端的超时时间长后,HystrixTimeoutException 仅在 之后创建 假装异常被抛出(由于“连接被拒绝”),因此延迟.

// 'cause' should be different due to timing
public HystrixRuntimeException(... Exception cause, Throwable fallbackException)

为了模拟超时,我想说你可以在服务器上强制超时,例如 Thread.sleep(6000) 停止服务器端的执行,或者只是在调试器上做一个断点。