跳到主要内容
版本:5.0.1

CircuitBreaker GatewayFilter 工厂

DeepSeek V3 中英对照 CircuitBreaker GatewayFilter Factory CircuitBreaker GatewayFilter Factory

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 GatewayFilter:

spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: https://example.org
filters:
- CircuitBreaker=myCircuitBreaker

要配置熔断器,请参阅您正在使用的底层熔断器实现的配置。

Spring Cloud CircuitBreaker 过滤器还可以接受一个可选的 fallbackUri 参数。目前仅支持 forward: 方案的 URI。如果调用了回退,请求将被转发到与该 URI 匹配的控制器。以下示例配置了这样的回退:

spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis
- RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint

下面的代码清单在 Java 中实现了相同的功能:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis"))
.rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088"))
.build();
}

此示例在调用断路器回退时转发到 /inCaseofFailureUseThis URI。请注意,此示例还演示了(可选的)Spring Cloud LoadBalancer 负载均衡(由目标 URI 上的 lb 前缀定义)。

CircuitBreaker 同样支持在 fallbackUri 中使用 URI 变量。这允许更复杂的路由选项,例如使用 PathPattern 表达式 转发原始主机或 URL 路径的部分内容。

在下面的示例中,调用 consumingServiceEndpoint/users/1 将被重定向到 inCaseOfFailureUseThis/users/1。

spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint/{*segments}
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/inCaseOfFailureUseThis/{segments}

主要场景是使用 fallbackUri 来定义网关应用程序内的内部控制器或处理程序。不过,您也可以将请求重新路由到外部应用程序中的控制器或处理程序,如下所示:

spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: CircuitBreaker
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback

在这个例子中,网关应用程序中没有 fallback 端点或处理器。然而,在另一个应用程序中存在一个,注册在 [localhost:9994](http://localhost:9994) 下。

当请求被转发至后备方案时,Spring Cloud CircuitBreaker Gateway 过滤器还会提供导致此情况的 Throwable。该异常会被添加到 ServerWebExchange 中,作为 ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR 属性,可在网关应用程序内处理后备方案时使用。

对于外部控制器/处理器的场景,可以通过添加包含异常详情的请求头来实现。你可以在FallbackHeaders GatewayFilter Factory 章节中找到更多相关信息。

基于状态码触发熔断器​

在某些情况下,您可能希望根据路由返回的状态码来触发熔断器。熔断器配置对象接受一个状态码列表,如果返回的状态码在列表中,就会触发熔断器。在设置触发熔断器的状态码时,您可以使用状态码的整数值,也可以使用 HttpStatus 枚举的字符串表示形式。

spring:
cloud:
gateway:
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"
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR"))
.rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088"))
.build();
}

无错误恢复​

当断路器跳闸或遇到错误时,你可以通过将 resumeWithoutError 设置为 true 来配置它恢复运行,而不将错误传播给客户端。这对于非关键服务非常有用,即使断路器失败,你也希望继续处理。

备注

当 resumeWithoutError 设置为 true 时,超时异常和熔断器开启异常(CallNotPermittedException)仍会返回其对应的 HTTP 状态码(504 Gateway Timeout 和 503 Service Unavailable)。只有其他未处理的异常才会导致成功响应。

spring:
cloud:
gateway:
routes:
- id: circuitbreaker_route
uri: lb://backing-service:8088
predicates:
- Path=/consumingServiceEndpoint
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
resumeWithoutError: true
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").setResumeWithoutError(true)))
.uri("lb://backing-service:8088"))
.build();
}