Spring Cloud Gateway如何实现熔断

时间:2024-03-20 19:58:48

Spring Cloud Gateway熔断集成

熔断应用:
金融市场中的熔断机制:在金融交易系统中,熔断机制(Circuit Breaker)是一种市场保护措施,旨在预防市场剧烈波动时可能导致的系统性风险。当某个基准指数(如股票指数或期货价格)在短时间内发生急剧上涨或下跌达到预先设定的阈值时,交易所会自动暂停交易一段时间或者限制涨跌幅度,类似于电器中的保险丝在电流过载时熔断以切断电流。例如,在美国股市中,曾经存在三级熔断机制,分别在标普500指数下跌7%、13%和20%时触发。
分布式计算中的熔断机制: 在分布式系统或微服务架构中,熔断机制是一种容错设计模式,其目的是防止因依赖的服务出现故障而引发整个系统的雪崩效应。当一个服务调用另一个服务时,如果后者频繁失败或响应时间过长,熔断器组件(如Hystrix、Resilience4j或Alibaba Sentinel)就会“熔断”该调用链路,不再继续请求有问题的服务,而是直接返回预设的错误信息或默认值,同时给调用方提供一个快速的失败反馈,而不是长时间等待或阻塞资源。在后续的一段时间内(冷却期),即使问题服务恢复,熔断器也可能保持打开状态,仅在一段时间后尝试半开状态重新发起调用,以确认服务是否真正恢复正常。这样可以确保整个系统的稳定性,并允许其他健康的服务不受影响地继续运行。

Spring Cloud Gateway 本身并不自带完整的熔断机制,但在早期版本中可以通过集成 Hystrix 来实现服务熔断和降级。然而,随着Hystrix的维护状态变更,社区推荐使用如Resilience4j或Alibaba Sentinel等其他更活跃的容错库。

SpringCloudGateway集成Hystrix实现熔断

第一步添加依赖:

在pom.xml或build.gradle文件中引入Spring Cloud Gateway与Hystrix的相关依赖。

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

第二部添加路由配置

在Spring Cloud Gateway配置中添加Hystrix过滤器,并定义相关的路由规则

  spring:
     cloud:
       gateway:
         routes:
           - id: your_route_id
             uri: lb://your_service_id
             predicates:
               - Path=/api/** # 例如,匹配所有/api开头的路径
             filters:
               - name: Hystrix
                 args:
                   name: fallbackcmd
                   fallbackUri: forward:/fallback  # 当熔断发生时转发到的本地fallback处理逻辑

第三步添加回退提示

创建一个Controller或Endpoint来处理当Hystrix触发熔断时的回退操作。

  @RestController
   public class FallbackController {

       @GetMapping("/fallback")
       public Mono<String> fallback() {
           return Mono.just("Fallback response due to service unavailable.");
       }
   }

第四步添加Hystrix熔断配置

确保Hystrix的全局配置已启用,并根据需要配置熔断阈值、超时时间等参数。

import com.netflix.hystrix.HystrixCommandProperties;

@Configuration
public class HystrixConfiguration {

    @Bean
    public HystrixCommandProperties.Setter hystrixCommandProperties() {
        return HystrixCommandProperties.Setter()
                .withExecutionTimeoutInMilliseconds(5000) // 设置命令执行超时时间为5秒
                .withCircuitBreakerEnabled(true) // 启用熔断器
                .withCircuitBreakerErrorThresholdPercentage(50) // 当错误率达到50%时触发熔断
                .withCircuitBreakerSleepWindowInMilliseconds(30000); // 熔断后的休眠窗口期为30秒
    }
}
hystrix:
  command:
    default: # 这里是全局默认配置,也可以针对特定命令键做单独配置
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 # 设置命令执行超时时间为5秒
      circuitBreaker:
        enabled: true # 启用熔断器
        errorThresholdPercentage: 50 # 当错误率达到50%时触发熔断
        sleepWindowInMilliseconds: 30000 # 熔断后的休眠窗口期为30秒

第五步实现熔断逻辑

自定义熔断 Hystrix Gateway Filter来完成熔断逻辑的适配。

参考
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class HystrixGatewayFilterFactory extends AbstractGatewayFilterFactory<HystrixGatewayFilterFactory.Config> {

    public static class Config {
        // 可配置属性,如命令名称、组键等
        private String commandKey;
        // 其他可能的配置项...

        // 构造函数和getters/setters省略...
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 创建Hystrix Command,封装请求处理逻辑
            HystrixCommand<String> command = new HystrixCommand<String>(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(config.getCommandKey()))) {
                @Override
                protected String run() throws Exception {
                    // 执行原始请求并获取响应
                    return chain.filter(exchange).block();
                }

                // 自定义fallback逻辑
                @Override

SpringCloudGateway集成Sentinel实现熔断

第一步配置依赖

 <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel-gateway</artifactId>
       <version>{latest_version}</version>
   </dependency>

  implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel-gateway:{latest_version}'

第二步配置拦截器

  spring:
     cloud:
       gateway:
         routes:
           - id: your_route_id
             uri: lb://your_service_id
             predicates:
               - Path=/your-api-path/**
             filters:
               - name: SentinelGatewayFilter
                 args:
                   resource: your_api_resource_name
                   limitApp: default # 可选,限制调用来源应用,默认不限制
                   fallbackUri: forward:/fallback  # 可选,设置降级处理逻辑路径

第三步启动sentinel服务

在这里插入图片描述

通过 Docker 镜像快速部署 Sentinel 控制台

拉取 Sentinel 控制台镜像: 在终端中运行以下命令从 Docker Hub 拉取最新的 Sentinel 控制台镜像:

docker pull bladex/sentinel-dashboard

运行 Sentinel 控制台容器: 使用以下命令创建并启动一个 Docker 容器,其中 -p 参数用于映射宿主机端口到容器内部的 Sentinel 控制台端口(默认为 8080),–name 参数用于指定容器名称,-d 参数表示在后台运行。

 docker run -d --name sentinel-dashboard -p 8080:8080 bladex/sentinel-dashboard

访问 Sentinel 控制台: Sentinel 控制台服务启动后,可以通过浏览器访问 http://localhost:8080 来登录控制台。默认用户名和密码都是 sentinel。

手动下载编译后的 jar 包运行

下载 Sentinel 控制台 jar 包: 访问 Sentinel GitHub Release 页面 下载最新版本的 sentinel-dashboard.jar 文件。
运行 Sentinel 控制台: 在下载目录下,使用 Java 运行该 jar 包,并指定端口号(例如 8080)

 java -jar sentinel-dashboard.jar --server.port=8080

访问 Sentinel 控制台: 同样地, Sentinel 控制台服务启动后,可以在浏览器中输入 http://localhost:8080 来访问和管理 Sentinel 策略。

配置熔断规则

登录 Sentinel 控制台,为之前定义的资源名称(例如 your_api_resource_name)配置流控、降级、系统保护等策略。
在这里插入图片描述

编写降级处理逻辑

如果在配置中指定了 fallbackUri,则需要在服务端实现对应的降级处理逻辑,当触发熔断时将执行这个逻辑。

yaml配置

在 Spring Cloud Gateway 的路由配置中,为 SentinelGatewayFilter 添加 fallbackUri 参数,指定一个本地处理熔断或降级的 URI。

 spring:
     cloud:
       gateway:
         routes:
           - id: your_route_id
             uri: lb://your_service_id
             predicates:
               - Path=/your-api-path/**
             filters:
               - name: SentinelGatewayFilter
                 args:
                   resource: your_api_resource_name
                   fallbackUri: forward:/fallback
具体实现

在您的 Spring Boot 应用中创建一个 Controller 或者 Endpoint 来处理这个 /fallback 请求。

@RestController
   public class FallbackController {

       @GetMapping("/fallback")
       public Mono<String> fallback(ServerWebExchange exchange) {
           // 这里可以根据需要自定义降级返回的内容
           return Mono.just("Fallback response due to service unavailable.");
       }
   }