SpringCloud Gateway - 集成 Sentinel 流量限流、熔断

简介: SpringCloud Gateway - 集成 Sentinel 流量限流、熔断

大家,今天发表一篇SpringCloud的文章,在做微服务架构时,通常要使用“网关”,来对内部服务进行统一的管理与鉴权,在新版的springcloud中,都会集成 Gateway,但gateway的功能毕竟有限,如何对内部服务进行保护与降级呢?

1.介绍

Alibaba Sentinel 支持对 Spring Cloud Gateway、Netflix Zuul 等主流的 API Gateway 进行限流与熔断配置。

本文将介绍如何在 Spring Cloud Gateway 中使用 Alibaba Sentinel 进行限流配置,从而代替 Hystrix.

2.集成步骤

2.1. 首先

需在Gateway网关模块引入以下依赖配置(以 Maven 为例):

  • 方案一: 只需引入 sentinel-spring-cloud-gateway-adapter 无需引入 spring-cloud-starter-alibaba-sentinel
    xml复制代码
    com.alibaba.csp
    sentinel-spring-cloud-gateway-adapter
    x.y.z

  • 方案二: 如果需要在Sentinel 控制台管理 网关模块的限流,那么推荐这种配置方式
    如果想引入 spring-cloud-starter-alibaba-sentinel 那么就把上面那个 adapter 替换成 spring-cloud-alibaba-sentinel-gateway

<!-- 没添加该依赖的话不能从application配置文件配置sentinel -->
 <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
   </dependency>
   <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
   </dependency>

2.2 SentinelGatewayBlockExceptionHandler

然后在使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可。

@Configurationpublic class GatewayConfiguration {
   
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
   
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
   
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
   
        return new SentinelGatewayFilter();
    }
}

2.3. 现在你可以选择在控制台中配置Sentinel限流规则 或者选择直接在Java代码中配置限流规则

2.3.1. 如果选择使用 Sentinel 控制台配置限流-熔断规则,那么还需要在 gateway 的配置文件中做出如下配置:
spring:
  cloud:
    # Sentinel 控制台连接配置
    sentinel:
      transport:
       # 当前服务与控制台交互的端口号,默认为8719,同一个机器上若有多个应用于控制台交互时需要设置成不同的端口
        port: 8739
        dashboard: 10.1.3.77:9090
      # 服务启动时直接建立心跳连接
      eager: true
      # Sentinel 储存规则的数据源配置(我这里使用的是Nacos来存储Sentinel的限流规则)
      datasource:
        ds:
          nacos:
            # Nacos 服务地址(可配置单点,或者集群的VIP地址)
            server-addr: 10.1.3.76:8848
            dataId: ${
   spring.application.name}-sentinel
            groupId: DEFAULT_GROUP
            namespace: sms-dev
            rule-type: flow
# Sentinel 控制台鉴权配置
sentinel:
  dashboard:
    auth:
      username: sentinel
      password: sentinel

此时你就可以在Sentinel控制台页面中配置限流规则,或者在你的 Nacos 配置中心中添加限流配置文件
sms-gateway-sentinel

[
    {
   
        "resource": "api-service",
        "limitApp": "default",
        "grade": 1,
        "count": 2,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    },
    {
   
        "resource": "url-proxy-1",
        "limitApp": "default",
        "grade": 1,
        "count": 2,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
2.3.2 如果你选择在Java代码中配置限流规则

下面是一个详细的配置示例

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.util.*;

/**
 * @description: 网关限流配置
 * @create: 2020-08-26 12:23
 **/
@Configuration
public class GatewaySentinelConfiguration {
   
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
    public GatewaySentinelConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                        ServerCodecConfigurer serverCodecConfigurer) {
   
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
   
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
   
        return new SentinelGatewayFilter();
    }
    /**
     * Spring 容器初始化的时候执行该方法
     */
    @PostConstruct
    public void doInit() {
   
        // 加载网关限流规则 
       initGatewayRules();
        // 加载自定义限流异常处理器
        initBlockHandler();
    }
    /**
     * 网关限流规则
     * 建议直接在 Sentinel 控制台上配置
     */
    private void initGatewayRules() {
   
        Set<GatewayFlowRule> rules = new HashSet<>();
        /*
            resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称
            count:限流阈值
            intervalSec:统计时间窗口,单位是秒,默认是 1 秒
         */
        // rules.add(new GatewayFlowRule("order-service")
        //         .setCount(3) // 限流阈值 
        //         .setIntervalSec(60)); // 统计时间窗口,单位是秒,默认是 1 秒
        // --------------------限流分组----------start----------

        rules.add(new GatewayFlowRule("url-proxy-1")
                .setCount(1) // 限流阈值
                .setIntervalSec(60)); // 统计时间窗口,单位是秒,默认是 1 秒
        rules.add(new GatewayFlowRule("api-service")
                .setCount(5) // 限流阈值
                .setIntervalSec(60)); // 统计时间窗口,单位是秒,默认是 1 秒
        // --------------------限流分组-----------end-----------
        // 加载网关限流规则
        GatewayRuleManager.loadRules(rules);
        // 加载限流分组
        initCustomizedApis();
        // ---------------熔断-降级配置-------------
        DegradeRule degradeRule = new DegradeRule("api-service") // 资源名称
                .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) // 异常比率模式(秒级)
                .setCount(0.5) // 异常比率阈值(50%)
                .setTimeWindow(10); // 熔断降级时间(10s)
        // 加载规则.
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
    }

    /**
     * 自定义限流异常处理器
     */
    private void initBlockHandler() {
   
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
    
           @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
   
                Map<String, String> result = new HashMap<>(3);
                result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
                result.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
                result.put("x","xx");
                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        //.body(BodyInserters.fromValue(result));
                        .body(BodyInserters.fromObject(result));
            }
        };
        // 加载自定义限流异常处理器 
       GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
    /**
     * 分组限流
     */
    private void initCustomizedApis() {
   
        //demo
        Set<ApiDefinition> definitions = new HashSet<>();
        // product-api 组
        ApiDefinition api1 = new ApiDefinition("product-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {
   {
   
                    // 匹配 /product-service/product 以及其子路径的所有请求
                    add(new ApiPathPredicateItem().setPattern("/product-service/product/**")
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        // order-api 组
        ApiDefinition api2 = new ApiDefinition("order-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {
   {
   
                    // 只匹配 /order-service/order/index 
                   add(new ApiPathPredicateItem().setPattern("/order-service/order/index"));
                }});
        definitions.add(api1);
        definitions.add(api2);
        // 加载限流分组
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }
}

Tips: 这种配置方式只适合固定的限流规则配置,如果需要灵活变动,那么建议使用上面那种方式

3. 总结

如果 Gateway 用 Sentinel

  • 建议在 Sentinel 控制台对 网关模块 进行具体的限流,熔断降级配置。
  • 否则还是推荐直接用 Gateway 内置的 RequestRateLimiter 跟 Hystrix 进行熔断限流配置。

还可以参考:

github.com/alibaba/Sen…

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度: 即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId* 在网关上用 Sentinel , 那么默认情况下一个 RouteId 对应的服务就是一个资源。
  • GatewayFlowRule: 网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。

自定义 API 维度: 用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

  • ApiDefinition:用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/ 和 /baz/ 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

  • 官方Demo 示例:

github.com/alibaba/Sen…

目录
相关文章
|
5月前
|
缓存 JSON NoSQL
别再手写过滤器!SpringCloud Gateway 内置30 个,少写 80% 重复代码
小富分享Spring Cloud Gateway内置30+过滤器,涵盖请求、响应、路径、安全等场景,无需重复造轮子。通过配置实现Header处理、限流、重试、熔断等功能,提升网关开发效率,避免代码冗余。
586 1
|
8月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
583 0
|
存储 数据可视化 Java
基于MicrometerTracing门面和Zipkin实现集成springcloud2023的服务追踪
Sleuth将会停止维护,Sleuth最新版本也只支持springboot2。作为替代可以使用MicrometerTracing在微服务中作为服务追踪的工具。
812 2
|
JSON Java API
利用Spring Cloud Gateway Predicate优化微服务路由策略
Spring Cloud Gateway 的路由配置中,`predicates`​(断言)用于定义哪些请求应该匹配特定的路由规则。 断言是Gateway在进行路由时,根据具体的请求信息如请求路径、请求方法、请求参数等进行匹配的规则。当一个请求的信息符合断言设置的条件时,Gateway就会将该请求路由到对应的服务上。
1357 69
利用Spring Cloud Gateway Predicate优化微服务路由策略
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
961 5
|
Java UED Sentinel
微服务守护神:Spring Cloud Sentinel,让你的系统在流量洪峰中稳如磐石!
【8月更文挑战第29天】Spring Cloud Sentinel结合了阿里巴巴Sentinel的流控、降级、熔断和热点规则等特性,为微服务架构下的应用提供了一套完整的流量控制解决方案。它能够有效应对突发流量,保护服务稳定性,避免雪崩效应,确保系统在高并发下健康运行。通过简单的配置和注解即可实现高效流量控制,适用于高并发场景、依赖服务不稳定及资源保护等多种情况,显著提升系统健壮性和用户体验。
378 1
|
监控 Java Sentinel
使用Sentinel进行服务调用的熔断和限流管理(SpringCloud2023实战)
Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
857 3
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
|
监控 Java Nacos
SpringCloud基础5——微服务保护、Sentinel
sentinel、雪崩问题、流量控制、隔离和降级、授权规则、规则持久化
SpringCloud基础5——微服务保护、Sentinel
|
监控 Java 应用服务中间件
SpringCloud面试之流量控制组件Sentinel详解
SpringCloud面试之流量控制组件Sentinel详解
1188 0

热门文章

最新文章