Skip to content

CircuitBreaker GatewayFilter 工厂

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

application.yml

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

要配置断路器本身,请参阅您正在使用的底层断路器实现(如 Resilience4J)的配置文档:

Spring Cloud CircuitBreaker 过滤器还可以接受一个可选的 fallbackUri 参数。目前,仅支持带有 forward: 协议(scheme)的 URI。如果触发了回退(Fallback)机制,请求将被转发到与该 URI 匹配的控制器。

以下示例配置了带有回退机制的路由:

application.yml

yaml
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 配置实现相同的功能:

Application.java

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。请注意,此示例还演示了(可选的)Spring Cloud LoadBalancer 负载均衡(由目标 URI 的 lb 前缀定义)。

CircuitBreaker 的 fallbackUri 还支持 URI 变量。这允许更复杂的路由选项,例如使用 PathPattern 表达式 将原始主机或 URL 路径的一部分转发到回退处理器。

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

application.yml

yaml
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 在网关应用程序内部定义一个内部控制器或处理程序。但是,您也可以将请求重定向到外部应用程序中的控制器或处理程序,如下所示:

application.yml

yaml
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

在这个例子中:

  1. 网关应用程序中没有 /fallback 端点或处理程序。
  2. 但是,在另一个应用程序(运行在 localhost:9994)中有一个处理程序。
  3. 网关定义了第二个路由 ingredients-fallback,用于匹配 /fallback 并将其转发到外部服务。

如果请求被转发到备用方案,Spring Cloud CircuitBreaker Gateway 过滤器还会提供导致该故障的原因。该异常原因会作为 ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR 属性添加到 ServerWebExchange 中,以便在处理备用方案时使用。

对于外部控制器/处理程序场景,可以添加包含异常详细信息的 Header。您可以在 FallbackHeaders GatewayFilter Factory 部分找到更多相关信息。

根据状态码触发熔断 (Tripping The Circuit Breaker On Status Codes)

在某些情况下,您可能需要根据路由返回的 HTTP 状态码来触发断路器。断路器配置对象接受一个状态码列表,当返回列表中的某个状态码时,断路器就会跳闸。 设置状态码时,您可以使用状态码的整数值(如 500),也可以使用 HttpStatus 枚举的字符串表示形式(如 "INTERNAL_SERVER_ERROR")。

application.yml

yaml
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"

Application.java

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").addStatusCode("INTERNAL_SERVER_ERROR"))
                .rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
        .build();
}

通俗易懂的教学 —— “家里的保险丝”

想象一下,你家里有很多电器(电视、冰箱、微波炉),这些就像是你的微服务。而 Spring Cloud Gateway 就像是你家里的总电闸/配电箱

1. 什么是 CircuitBreaker(断路器)?

通俗解释: CircuitBreaker 就是保险丝

  • 正常情况:电流顺畅通过,电器正常工作(请求正常转发给微服务)。
  • 出故障了:如果微波炉突然短路了(微服务挂了或者响应极慢),电流过大。
  • 没有保险丝:电线会烧坏,甚至引发火灾,把隔壁冰箱也烧坏(由于请求堆积,耗尽网关资源,导致整个网关崩溃,所有服务都不可用 —— 这叫雪崩效应)。
  • 有保险丝:保险丝“啪”的一声断开(熔断)。微波炉没电了,但是电视和冰箱还能正常用。网关会告诉用户:“微波炉暂时坏了,请稍后再试”,而不是让用户一直干等。

2. 配置里的关键参数是什么意思?

  • name: myCircuitBreaker:给这个保险丝起个名字。
  • fallbackUri: forward:/fallback:这就是备用方案(兜底)
    • 场景:你点外卖,系统去调用“商家服务”获取菜单。
    • 故障:“商家服务”挂了,超时了。
    • 熔断发生:保险丝断开。
    • Fallback:网关自动把请求转发到 /fallback。这个 /fallback 可能返回一张图片:“哎呀,系统繁忙,请稍后再试”,或者返回一个缓存的旧菜单。
    • 好处:用户看到的是友好的提示,而不是由浏览器报出的 500 Internal Server Error 或者在那转圈圈转到死。

3. 什么是“根据状态码熔断”?

默认情况下,只有微服务完全连不上或者超时,保险丝才会断。 但是,有时候微服务虽然连上了,却返回了错误的信息,比如 500(服务器内部错误)

  • 配置 statusCodes: 500:意思是告诉网关,“只要那个微服务敢给我返回 500 错误,我就当它坏了,直接拉闸!走备用方案!”

4. 总结

在 Spring Cloud Gateway 中配置 CircuitBreaker 只有三步:

  1. 加依赖:买保险丝(引入 spring-cloud-starter-circuitbreaker-reactor-resilience4j)。
  2. 配过滤器:把保险丝装进电路里(在 yaml 里配置 filters: - CircuitBreaker=...)。
  3. 写兜底逻辑:想好保险丝断了该怎么办(写一个 /fallback 接口返回友好提示)。

这样,你的系统就从“一碰就倒”变成了“坚不可摧”的堡垒!


Based on Spring Framework.