CircuitBreaker 過濾器

Spring Cloud CircuitBreaker GatewayFilter 工廠使用 Spring Cloud CircuitBreaker API 將閘道器路由包裝在斷路器中。Spring Cloud CircuitBreaker 支援多個可用於 Spring Cloud Gateway 的程式庫。Spring Cloud 預設支援 Resilience4J。

若要啟用 Spring Cloud CircuitBreaker 過濾器,您需要將 spring-cloud-starter-circuitbreaker-reactor-resilience4j 放在類別路徑中。以下範例設定 Spring Cloud CircuitBreaker 過濾器

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: circuitbreaker_route
          uri: https://example.org
          filters:
          - CircuitBreaker=myCircuitBreaker
GatewaySampleApplication.java
import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCircuitBreakerNoFallback() {
        return route("circuitbreakernofallback")
                .route(path("/anything/circuitbreakernofallback"), http("https://example.org"))
                .filter(circuitBreaker("mycb3"))
                .build();
    }
}

若要設定斷路器,請參閱您正在使用的底層斷路器實作的組態。

Spring Cloud CircuitBreaker 過濾器也可以接受選用的 fallbackUri 參數。目前,僅支援 forward: 方案的 URI。如果呼叫了後備,請求將轉發到 URI 比對的控制器。以下範例設定了這樣的後備

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: circuitbreaker_route
          uri: https://example.org
          predicates:
          - Path=/consumingServiceEndpoint
          filters:
          - name: CircuitBreaker
            args:
              name: myCircuitBreaker
              fallbackUri: forward:/inCaseOfFailureUseThis

以下列表在 Java 中執行相同的操作

GatewaySampleApplication.java
import java.net.URI;
import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCircuitBreakerFallback() {
        return route("circuitbreaker_route")
                .route(path("/consumingServiceEndpoint"), http("https://example.org"))
                .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis")))
                .build();
    }
}

當呼叫斷路器後備時,此範例會轉發到 /inCaseofFailureUseThis URI。

CircuitBreaker 也支援 fallbackUri 中的 URI 變數。這允許更複雜的路由選項,例如使用 PathPattern 表達式 轉發原始主機或 URL 路徑的區段。

在以下範例中,呼叫 consumingServiceEndpoint/users/1 將重新導向至 inCaseOfFailureUseThis/users/1

GatewaySampleApplication.java
import java.net.URI;
import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCircuitBreakerFallback() {
        return route("circuitbreaker_route")
                .route(path("/consumingServiceEndpoint/{*segments}"), http("https://example.org"))
                .filter(circuitBreaker("myCircuitBreaker", URI.create("forward:/inCaseOfFailureUseThis/{segments}")))
                .build();
    }
}

主要情境是使用 fallbackUri 在閘道器應用程式中定義內部控制器或處理常式。但是,您也可以將請求重新路由到外部應用程式中的控制器或處理常式,如下所示

GatewaySampleApplication.java
import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker;
import static org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions.lb;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCircuitBreakerFallbackToGatewayRoute() {
        return route("ingredients")
                .route(path("/ingredients/**"), http())
                .filter(lb("ingredients"))
                .filter(circuitBreaker("fetchIngredients", URI.create("forward:/fallback")))
                .build()
            .and(route("ingredients-fallback")
                .route(path("/fallback"), http("http://localhost:9994"))
                .build());
    }
}

在此範例中,閘道器應用程式中沒有 fallback 端點或處理常式。但是,在另一個應用程式中,有一個在 localhost:9994 下註冊。

在請求轉發到後備的情況下,Spring Cloud CircuitBreaker Gateway 過濾器也提供導致請求轉發的 Throwable。它會以 MvcUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR 屬性新增至 ServerRequest,該屬性可在閘道器應用程式中處理後備時使用。

對於外部控制器/處理常式情境,可以新增包含例外詳細資訊的標頭。您可以在 FallbackHeaders 過濾器章節 中找到有關這樣做的更多資訊。

在狀態碼上觸發斷路器

在某些情況下,您可能想要根據它包裝的路由傳回的狀態碼來觸發斷路器。斷路器組態物件會取得狀態碼清單,如果傳回這些狀態碼,將導致斷路器被觸發。設定您想要觸發斷路器的狀態碼時,您可以使用具有狀態碼值的整數或 HttpStatus 列舉的字串表示法。

application.yml
spring:
  cloud:
    gateway:
      mvc:
        routes:
        - id: circuitbreaker_route
          uri: lb://backing-service:8088
          predicates:
          - Path=/consumingServiceEndpoint
          filters:
          - name: CircuitBreaker
            args:
              name: myCircuitBreaker
              fallbackUri: forward:/inCaseOfFailureUseThis
              statusCodes:
                - 500
                - "NOT_FOUND"
GatewaySampleApplication.java
import java.net.URI;
import static org.springframework.cloud.gateway.server.mvc.filter.CircuitBreakerFilterFunctions.circuitBreaker;
import static org.springframework.cloud.gateway.server.mvc.filter.LoadBalancerFilterFunctions.lb;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;

@Configuration
class RouteConfiguration {

    @Bean
    public RouterFunction<ServerResponse> gatewayRouterFunctionsCircuitBreakerFallback() {
        return route("circuitbreaker_route")
                .route(path("/consumingServiceEndpoint"), http())
                .filter(lb("backing-service"))
				.filter(circuitBreaker(config -> config.setId("myCircuitBreaker").setFallbackUri("forward:/inCaseOfFailureUseThis").setStatusCodes("500", "NOT_FOUND")))
                .build();
    }
}