【问题标题】:Configure specific breaker for route with Resilience4j in Spring cloud gateway在 Spring Cloud Gateway 中使用 Resilience4j 为路由配置特定的断路器
【发布时间】:2020-03-11 17:41:00
【问题描述】:

我尝试在我的 spring 云网关中配置 Resilience4j,但没有成功。 我发现的都是 Hystrix 或纯 java 的。

我已经将网关配置为在我的服务上传输请求,没关系。

但是不可能在上面配置resilience4j。我有一个很好的 R4J 响应式神器。

Spring Cloud API 和网关中Resilience4j 的配置不同?

查看我的配置文件。

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: helloworld_service
          uri: "https://localhost:8080"
          predicates:
            - Path=/helloworld/**
          filters:
            - RewritePath=/helloworld/(?<segment>.*), /$\{segment}
            - name: CircuitBreaker
              args:
                name: helloworld
      httpclient:
        ssl:
          useInsecureTrustManager: true

# RESILIENCE4J PROPERTIES
resilience4j:
  circuitbreaker:
    configs:
      default:
        #registerHealthIndicator: true
        ringBufferSizeInClosedState: 10
        ringBufferSizeInHalfOpenState: 3
        automaticTransitionFromOpenToHalfOpenEnabled: true
        waitDurationInOpenStateMillis: 2000
        failureRateThreshold: 50
        eventConsumerBufferSize: 10
    instances:
      helloworld:
        baseConfig: default
        ringBufferSizeInClosedState: 5

我的依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>

并且产生的错误:

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name CircuitBreaker
Caused by: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name CircuitBreaker

非常感谢您的帮助。

【问题讨论】:

  • 您找到解决方案了吗?
  • 嗨,Bilak,不是...你有什么想法吗?

标签: spring-cloud-gateway resilience4j


【解决方案1】:

如果要为 Resuliience4j 断路器使用外部配置,则需要添加以下依赖项:

<dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-gateway</artifactId>
       </dependency>
       <dependency>
           <groupId>io.github.resilience4j</groupId>
           <artifactId>resilience4j-spring-boot2</artifactId>
           <version>1.1.0</version>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>

然后在您的 spring 网关应用程序中,使用您在 spring 云工厂中的外部配置注入加载的 Circuitbreaker 注册表:

    @Bean
    public ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory(CircuitBreakerRegistry circuitBreakerRegistry) {
        ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory = new ReactiveResilience4JCircuitBreakerFactory();
        reactiveResilience4JCircuitBreakerFactory.configureCircuitBreakerRegistry(circuitBreakerRegistry);
        return reactiveResilience4JCircuitBreakerFactory;
    }

然后在 applciation yml 文件中添加您的外部断路器配置,例如:

esilience4j.circuitbreaker:
  configs:
    default:
      slidingWindowSize: 10
      minimumNumberOfCalls: 5
      permittedNumberOfCallsInHalfOpenState: 3
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitDurationInOpenState: 2s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
      ignoreExceptions:
        - java.lang.IllegalStateException
    shared:
      slidingWindowSize: 100
      permittedNumberOfCallsInHalfOpenState: 30
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      ignoreExceptions:
        - java.lang.IllegalStateException
  instances:
    backendA:
      baseConfig: default

使用配置的断路器名称在您的路由中启用断路器过滤器,例如:

spring:
  application:
    name: gateway-service
  output.ansi.enabled: ALWAYS
  cloud:
    gateway:
      routes:
        - id: test-service-withResilient4j
          uri: http://localhost:8091
          predicates:
            - Path=/testService/**
          filters:
            - CircuitBreaker=backendA
            - RewritePath=/testService/(?<path>.*), /$\{path}

现在应该用你的外部配置断路器来保护它,否则你可以通过定制器的代码配置方法来配置它

【讨论】:

  • 谢谢Mahmoud,我现在正在度假,我会很快回复所有回复。
  • 我实际上也遇到了同样的问题。我已经尝试了这些步骤,但我收到了org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'backendA' cannot be found on object of type 'org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator$DelegatingServiceInstance' - maybe not public or not valid?
  • @DarylRobbins 你有我可以在 github 上查看的代码示例吗?
  • 如何将断路器实例与非基于属性的 RouteLocator 中的路由相关联?过滤器: - CircuitBreaker=auth-service
【解决方案2】:

当前 spring-cloud-gateway Hoxton.RELEASE 自动配置有问题。您可以通过以下配置解决它。

@Configuration
public class Resilience4JConfiguration {

    @Bean
    public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
        return new FallbackHeadersGatewayFilterFactory();
    }

    @Bean
    public SpringCloudCircuitBreakerFilterFactory resilience4JCircuitBreakerFactory(
            ReactiveResilience4JCircuitBreakerFactory reactiveCircuitBreakerFactory,
            ObjectProvider<DispatcherHandler> dispatcherHandlers) {
        return new SpringCloudCircuitBreakerResilience4JFilterFactory(reactiveCircuitBreakerFactory, dispatcherHandlers);
    }

}

【讨论】:

  • 嗨,Bilak,感谢您的回答。看来我可以用你的解决方案编译。但是我的resilience4j配置没有被使用:(除了我的问题之外,我是否需要添加另一个配置?并且通过配置,应用程序找不到ReactiveResilience4JCircuitBreakerFactory的实例。它不是由spring自动创建的吗?
  • SCG 的 R4j 的配置是 here 和你用的不一样
  • 谢谢,Bilak,我的默认断路器似乎可用。如果你同意,就一点点。我创建了一个自定义断路器来覆盖默认的一些属性,但我不明白如何为我的路线选择它。我在路由的 args 中添加了此配置的名称,但未使用。 yaml fitlers: - name: CircuitBreaker args: name: helloworldCircuitBreaker java setCircuitBreakerConfig(CircuitBreakerConfig.custom().minimumNumberOfCalls(10).failureRateThreshold(20).build()), "helloworldCircuitBreaker");
  • 可能会发布该配置的完整示例,在 cmets 中不太可读。
【解决方案3】:

感谢 Bilak 的耐心。

我对 Resilience4j 的配置:

@Configuration
public class Resilience4JConfiguration {

    /**
     * Default Resilience4j circuit breaker configuration
     */
    @Bean
    public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .circuitBreakerConfig(CircuitBreakerConfig.custom().minimumNumberOfCalls(5).failureRateThreshold(20).build())
                .build());
    }

    @Bean
    public Customizer<ReactiveResilience4JCircuitBreakerFactory> helloworldCircuitBreaker(){
        return factory -> {
          factory.configure(builder -> builder.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build()
                  .setCircuitBreakerConfig(CircuitBreakerConfig.custom().minimumNumberOfCalls(10).failureRateThreshold(20).build())
                  , "helloworldCircuitBreaker");
        };
    }

    @Bean
    public Customizer<ReactiveResilience4JCircuitBreakerFactory> accountCircuitBreaker(){
        return factory -> {
            factory.configure(builder -> builder.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build(), "accountCircuitBreaker");
        };
    }

    @Bean
    public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
        return new FallbackHeadersGatewayFilterFactory();
    }

    @Bean
    public SpringCloudCircuitBreakerFilterFactory resilience4JCircuitBreakerFactory(
            ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory,
            ObjectProvider<DispatcherHandler> dispatcherHandlers) {
        return new SpringCloudCircuitBreakerResilience4JFilterFactory(reactiveCircuitBreakerFactory, dispatcherHandlers);
    }
}

我的应用程序.yaml:

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: helloworld_service
          uri: "https://localhost:8080"
          predicates:
            - Path=/helloworldservice/**
          filters:
            - CircuitBreaker

有了这个配置,它使用的默认配置就正确了。

但如果我尝试精确指定特定的断路器,则不会使用任何配置(没有默认值,也没有 helloworldCircuitBreaker)

配置特定断路器:

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: helloworld_service
          uri: "https://localhost:8080"
          predicates:
            - Path=/helloworldservice/**
          filters:
            - name: CircuitBreaker
            args:
              name: helloworldCircuitBreaker

【讨论】:

  • 好吧,我认为您需要在 CB 示例中添加自定义程序所以 factory.addCircuitBreakerCustomizer。然后它就可以工作了。
  • 能否请您帮助如何使用定制器配置创建定制器断路器?
【解决方案4】:

确保添加了以下依赖项:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

现在在您的 spring 网关应用程序中,创建 bean:

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
            .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
            .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build()).build());
}

现在,application.yml 应该是这样的

spring:
application:
  name: CLOUD-GATEWAY
cloud:
  gateway:
    routes:
    - id: order-service
      uri: lb://ORDER-SERVICE
      predicates:
      - Path=/orders**
      filters:
        - name: CircuitBreaker
          args:
            name: order-service
            fallbackuri: forward:/fallback/orders

【讨论】:

    猜你喜欢
    • 2021-06-12
    • 2020-01-27
    • 2021-08-07
    • 1970-01-01
    • 2023-01-21
    • 2020-11-02
    • 2023-03-09
    • 1970-01-01
    • 2021-02-02
    相关资源
    最近更新 更多