SpringCloudAlibaba Gateway(三)-整合Sentinel功能路由维度、API维度进行流控

39 篇文章 2 订阅
19 篇文章 2 订阅

Gateway整合Sentinel

​ 前面使用过Sentinel组件对服务提供者、服务消费者进行流控、限流等操作。除此之外,Sentinel还支持对Gateway、Zuul等主流网关进行限流。

​ 自sentinel1.6.0版开始,Sentinel提供了Gateway的适配模块,能针对路由(route)和自定义API分组两个维度进行限流。

路由维度

路由维度是指配置文件中的路由条目,资源名是对应的routeId,相比自定义API维度,这是比较粗粒度的。看下如何实现:

  1. 导入Sentinel组件为Gateway提供的适配依赖包,在pom.xml中导入依赖

    <!--sentinel为gateway提供的适配包-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    </dependency>
    
  2. 增加配置类SentinelRouteConfiguration,实例化SentinelGatewayFilterSentinelBlockExceptionHandler对象,初始化限流规则

    @Configuration  // 配置类
    public class SentinelRouteConfiguration {   // 路由限流规则配置类
    
        private final List<ViewResolver> viewResolvers;
    
        private final ServerCodecConfigurer serverCodecConfigurer;
    
    
        public SentinelRouteConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
            this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
            this.serverCodecConfigurer = serverCodecConfigurer;
        }
    
        @PostConstruct
        public void initGatewayRules() {    // 初始化限流规则
            Set<GatewayFlowRule> rules = new HashSet<>();
            GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("user_route");    // 资源名(gateway中的路由id)
            gatewayFlowRule.setCount(1);    // 限流阈值
            gatewayFlowRule.setIntervalSec(1);  // 统计时间窗口,默认1s
    
            rules.add(gatewayFlowRule);
            GatewayRuleManager.loadRules(rules);    // 载入规则
        }
    
        @PostConstruct
        public void initBlockHandlers() {    // 限流后的响应
            BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
                Map<String, Object> result = new HashMap<>();
                result.put("code", "0");
                result.put("message", "您已被限流");
                return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(result));
            };
    
            GatewayCallbackManager.setBlockHandler(blockRequestHandler);    // 设置限流响应
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
            return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter sentinelGatewayFilter() {   // 初始化限流过滤器
            return new SentinelGatewayFilter();
        }
    
    }
    

    注意:Gateway限流是通过Filter实现的,主要是注入SentinelGatewayFilter实例和SentinelGatewayBlockExceptionHandler实例

  3. 在yml中,设置两个route,user_routeshop_route,上面主要是对user_route限流了,着重看下

    server:
      port: 8083
    
    spring:
      application:
        name: gateway   # 服务名
    
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # nacos地址
        gateway:
          routes: # 路由,可配置多个
          - id: user_route  # 路由id,唯一即可,默认UUID
            uri: lb://user  # 路由地址(匹配成功后的服务地址) user是用户服务的服务名称
            order: 1  # 路由优先级,默认0,越低优先级越高
            predicates:
            - Path=/user/**   # 断言,匹配规则
    
          - id: shop_route  # 路由id,唯一即可,默认UUID
            uri: lb://shop  # 路由地址(匹配成功后的服务地址) shop是用户服务的服务名称
            order: 1  # 路由优先级,默认0,越低优先级越高
            predicates:
            - Path=/shop/**   # 断言,匹配规则
    
  4. 启动服务开始调试

    在这里插入图片描述

    成功完成路由级别的限流,那么后面看看API维度的限流

自定义API维度

​ 上面那种限流方式可以看出灵活性不够高。自定义的API维度可以利用Sentinel提供的API自定义分组来进行限流。相比路由维度,这是一种更加细粒度的限流方式。

实现

  1. 导入Gateway的适配包

    <!--sentinel为gateway提供的适配包-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
    </dependency>
    
  2. 依然是实例化SentinelGatewayFilterSentinelBlockExceptionHandler对象,初始化限流规则,定义API分组

    @Configuration  // 配置类
    public class SentinelRouteConfiguration {   // 路由限流规则配置类
    
        private final List<ViewResolver> viewResolvers;
    
        private final ServerCodecConfigurer serverCodecConfigurer;
    
    
        public SentinelRouteConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
            this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
            this.serverCodecConfigurer = serverCodecConfigurer;
        }
    
        @PostConstruct
        public void initGatewayRules() {    // 初始化限流规则
            Set<GatewayFlowRule> rules = new HashSet<>();
            GatewayFlowRule gatewayFlowRule = new GatewayFlowRule("user_api");    // 资源名,api分组的名称(自定义)
            gatewayFlowRule.setCount(1);    // 限流阈值
            gatewayFlowRule.setIntervalSec(1);  // 统计时间窗口,默认1s
    
            rules.add(gatewayFlowRule);
            GatewayRuleManager.loadRules(rules);    // 载入规则
        }
    
        @PostConstruct
        public void initCustomizedApis() {
            Set<ApiDefinition> apiDefinitions = new HashSet<>();
            ApiDefinition apiDefinition = new ApiDefinition("user_api") // 定义 api分组
                    .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                            add(new ApiPathPredicateItem()
                                    .setPattern("/user/group/**")	// 路径匹配规则
                                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); // 匹配策略,前缀匹配
                        }});
            apiDefinitions.add(apiDefinition);
    
            GatewayApiDefinitionManager.loadApiDefinitions(apiDefinitions); // 载入API分组定义
    
        }
    
        @PostConstruct
        public void initBlockHandlers() {    // 限流后的响应
            BlockRequestHandler blockRequestHandler = (serverWebExchange, throwable) -> {
                Map<String, Object> result = new HashMap<>();
                result.put("code", "0");
                result.put("message", "您已被限流");
                return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(result));
            };
    
            GatewayCallbackManager.setBlockHandler(blockRequestHandler);    // 设置限流响应
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
            return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
        }
    
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE)
        public GlobalFilter sentinelGatewayFilter() {   // 初始化限流过滤器
            return new SentinelGatewayFilter();
        }
    
    }
    

    唯一要注意的是:路由匹配规则如果是单一的一个具体接口,不是匹配符,那么后面的匹配策略就没有必要再去配置了(setMatchStrategy()方法)

  3. 定义一个/user/group/findById接口

    @RequestMapping("/user/group/findById")
    public String findGById(@RequestParam("id") Integer id) {
        return userInfo.getOrDefault(id, null);
    }
    
  4. 启动调用测试

    在这里插入图片描述

    可以看到配置的没有问题,满足/user/group/**规则的请求,有被限流到

超时配置

Gateway默认没有超时的限制,也就是数据什么时候返回,就等待到什么时候。如果不想等待,可以增加对超时的配置

gateway:
  httpclient:
    connect-timeout: 5000 # 建立连接时间限制,单位毫秒
    response-timeout: 4s  # 响应时间的时间限制

尝试下,接口睡眠5s,再次调用

curl localhost:8083/user/group/findById?id=1
{"timestamp":"2023-09-02T00:59:47.184+00:00","path":"/user/group/findById","status":504,"error":"Gateway Timeout","requestId":"7f5ff558-1"}

被告知504,超时了~

CORS配置

涉及到前后端分离的跨域请求时,浏览器访问后端地址通常提示No Access-Control-Allow-Origin header is present on the requested resource

可以在gateway中增加跨域配置,或者前端去配置都可以,自行协商。

cloud:
  nacos:
    discovery:
      server-addr: localhost:8848 # nacos地址
  gateway:
    httpclient:
      connect-timeout: 5000 # 建立连接时间限制,单位毫秒
      response-timeout: 4s  # 响应时间的时间限制
    globalcors:
      cors-configurations: 
        '[/**]':
          allowedOrigins: "*" # 允许的来源
          allowedMethods: "*" # 允许的方法
          allowedHeaders: "*" # 允许的请求头  *表示所有

通常情况下,也可以不是按照全部允许来做,按照你的项目实际开发需求搞就行了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spring-cloud-starter-alibaba-sentinel是一款用于微服务架构中实现流量控制、熔断降级、系统负载保护等功能API库。 首先,它可以实现流量控制,通过设置限流规则,对微服务进行限制,避免大量请求进入服务,导致服务不可用或资源耗尽。可以设置QPS、线程数、并发数等限制条件,对请求进行控制,保障系统的稳定性。 其次,它还支持熔断降级功能。当微服务出现异常或超时时,它会根据预设的熔断规则,将服务降级,避免故障的扩散。可以通过设置异常比例、异常数等规则,对服务进行自动降级,保障系统的可用性。 另外,它还支持系统负载保护功能。通过设置系统负载的阈值,当系统负载超过一定限制时,它会自动出发保护机制,拒绝服务请求,保护系统免受过载的影响。可以设置CPU使用率、内存使用率等指标来判断系统负载情况,保持系统的稳定运行。 此外,spring-cloud-starter-alibaba-sentinel还提供了实时监控、统计和报警功能,可以通过可视化的控制台查看服务的运行状态和性能指标,及时发现问题并进行相应的调整和优化。 总之,spring-cloud-starter-alibaba-sentinel是一款功能强大的API库,可以帮助开发人员在微服务架构中实现流量控制、熔断降级、系统负载保护等功能,确保系统的稳定性和可用性。它可以有效地保护系统不受高流量、异常情况和系统负载的影响,提高系统的弹性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值