SpringCloudAlibabaSentinel实现网关动态限流

目录

1.SpringCloudAlibabaSentinel实现网关动态限流

1.概念和来历

2.概览及控制台搭建

3.控制台有哪些能力

4.功能及设计理念

5.限流的几种方法

2.SpringCloud Alibaba Sentinel 的降级功能

1.yml中添加配置

2.编写配置类

3.编写兜底工具类

3.Sentinel还对Feigin实现了适配,支持Fenig的容错降级

3.1启动类添加注解

3.2编写feign接口

3.3编写Sentinel 对 OpenFeign 接口的降级策略

4.Sentinel结合Nacos实现限流规则持久化

4.1sentinel存储在nacos中限流数据结构

4.2添加依赖

4.3在限流资源添加限流规则

4.4在yml文件中添加配置

5.GeteWay集成Sentinel实现网关限流

5.1最简单、也是常用的测试方式:在网关内硬编码实现对请求的限流

5.2配置文件的方式编写限流规则

5.3Gateway集成Nacos+Sentiel实现网关动态限流

6.为什么需要限流


1.SpringCloudAlibabaSentinel实现网关动态限流

1.概念和来历

Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。
Sentinel的来历
1.2012年,Sentinel 诞生,主要功能为入口流量控制
2.2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景
3.2018 年,Sentinel 开源,并持续演进
​
SpringCloud Alibaba Sentinel 的基本概念
资源:可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码
方法签名 URL 服务名
规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则:且所有规则可以动态实时调整

2.概览及控制台搭建

Sentinel提供一个轻量级的开源控制台(单机和集群),规则管理和推送的功能
获取并启动 Sentinel Dashboard (控制台
​
1.下载控制台 Jar 包: https://github.com/alibaba/Sentinel/releases
# 创建命令
mkdir -p /usr/local/sentinel
​
cd  /usr/local/sentinel
#下载1.8.0版本
wget https://github.com/alibaba/Sentinel/releases/download/1.8.1/sentinel-dashboard-1.8.1.jar
​
2.nohup  java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=butool-sentinel-dashboard -jar /usr/local/sentinel/sentinel-dashboard-1.8.1.jar &
​
3.从Sentinel 1.6.0 起,Sentinel Dashboard 引入了基本的登录功能,默认的用户名密码都是 sentinel
​
4.打开防火墙端口
firewall-cmd --zone=public --add-port=7777/tcp --permanent
firewall-cmd --reload
​
4.访问地址
ip:7777

3.控制台有哪些能力

1.查看机器列表以及健康情况: 收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线
​
2.监控(单机和集群聚合): 通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控
​
3.规则管理和推送:统一管理推送规则

4.功能及设计理念

4.1流量控制

流量控制在网络传输中是一个常用的概念,
它用于调整网络包的发送数据。
然而,从系统稳定性角度考虑,
在处理请求的速度上,也有非常多的讲究。
任意时间到来的请求往往是随机不可控的,
而系统的处理能力是有限的。
我们需要根据系统的处理能力对流量进行控制。
Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,
如下图所示:

4.2流量控制设计理念

流量控制有以下几个角度:
​
1.资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
​
2.运行指标,例如 QPS、线程池、系统负载等;
​
3.控制的效果,例如直接限流、冷启动、排队等。
​
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

5.限流的几种方法

1.硬编码方式

1.yml文件里添加sentinel服务端地址
2.在资源方法上添加注解@SentinelResource(value="方法名")
3.配置初始化方法指定资源为SentinelResource.value
4.设置一秒请求几次
5.完成请求
6.控制台可以看到流控资源列表,看不到可能懒加载就请求一次

2.设置自定义返回信息

1.在controller中添加方法,返回值和Request方法一致,入参为BlockException
2.获取错误信息BlockException.getRuleLimitApp()
3.@SentinelResource注解中添加属性flowHandle值为方法名称
4.连续请求两次会看到结果

3.自定义通用的限流逻辑

1.创建类类中需要写静态方法,sentinel不会对对象进行new操作 
2.方法返回值和Request方法一致,入参为BlockException
3.获取错误信息BlockException.getRuleLimitApp()
4.@SentinelResource注解中添加属性flowHandleClass值为类名,@SentinelResource.bolckHandler值为静态方法名称

4.基于sentinel控制台配置流控规则,根据资源名称

1.sentinel懒加载需要请求一次就会在控制台上看到资源
2.定义controller方法在控制台新增流控规则根据资源名称
@SentinelResource(
value ="byResource",blockHandler ="qinyiHandleBlockException"blockHandlerClass = ButoolBlockHandler.class
public CommonResponse<String> byResource() {}
请求一次后在控制台配置限流规则

5.在“簇点链路”中给 url 添加流控规则

在“簇点链路”中给 url 添加流控规则
@SentinelResource(value = "byUrl")public CommonResponse<String> byUrl{}
在控制台簇点链路中新增流控规则

2.SpringCloud Alibaba Sentinel 的降级功能

1.Sentinel 支持对 RestTemplate 服务调用进行保护,实现流控降级和异常降级
2.在构造RestTempplate这bean上添加@SentinelRestTemplate注解

1.yml中添加配置

# 开启或关闭 @SentinelRestTemplate 注解
resttemplate:
  sentinel:
    enabled: true

2.编写配置类

package cn.butool.conf;
​
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
​
/**
 * <h1>开启服务间的调用保护, 需要给 RestTemplate 做一些包装</h1>
 * */
@Slf4j
@Configuration
public class SentinelConfig {
​
    /**
     * <h2>包装 RestTemplate</h2>
     * */
    @Bean
//    @SentinelRestTemplate(
//            fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class,
//            blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class
//    )
    public RestTemplate restTemplate() {
        return new RestTemplate();  // 可以对其做一些业务相关的配置
    }
}

3.编写兜底工具类

package cn.butool.conf;
​
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.imooc.ecommerce.vo.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
​
/**
 * <h1>RestTemplate 在限流或异常时的兜底方法</h1>
 * */
@Slf4j
public class RestTemplateExceptionUtil {
​
    /**
     * <h2>限流后的处理方法</h2>
     * */
    public static SentinelClientHttpResponse handleBlock(HttpRequest request,
                                                         byte[] body,
                                                         ClientHttpRequestExecution execution,
                                                         BlockException ex) {
        log.error("Handle RestTemplate Block Exception: [{}], [{}]",
                request.getURI().getPath(), ex.getClass().getCanonicalName());
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new JwtToken("butool-block"))
        );
    }
​
    /**
     * <h2>异常降级之后的处理方法</h2>
     * */
    public static SentinelClientHttpResponse handleFallback(HttpRequest request,
                                                            byte[] body,
                                                            ClientHttpRequestExecution execution,
                                                            BlockException ex) {
        log.error("Handle RestTemplate Fallback Exception: [{}], [{}]",
                request.getURI().getPath(), ex.getClass().getCanonicalName());
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new JwtToken("butool-block"))
        );
    }
}

3.Sentinel还对Feigin实现了适配,支持Fenig的容错降级

## 打开 Sentinel 对 Feign 的支持
feign:
  sentinel:
    enabled: true

3.1启动类添加注解

@EnableFeignClients

3.2编写feign接口

/**
 * <h1>通过 Sentinel 对 OpenFeign 实现熔断降级</h1>
 * */
@FeignClient(
        value = "e-commerce-butool",
        fallback = SentinelFeignClientFallback.class
)
public interface SentinelFeignClient {
​
    @RequestMapping(value = "busl", method = RequestMethod.GET)
    CommonResponse<String> getResultByFeign(@RequestParam Integer code);
}
​

3.3编写Sentinel 对 OpenFeign 接口的降级策略

import cn.butool.vo.CommonResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
​
/**
 * <h1>Sentinel 对 OpenFeign 接口的降级策略</h1>
 * */
@Slf4j
@Component
public class SentinelFeignClientFallback implements SentinelFeignClient {
​
    @Override
    public CommonResponse<String> getResultByFeign(Integer code) {
​
        log.error("request supply for test has some error: [{}]", code);
        return new CommonResponse<>(
                -1,
                "sentinel feign fallback",
                "input code: "+ code
        );
    }
}

4.Sentinel结合Nacos实现限流规则持久化

1.Sentinel Dashboard 将规则保存在内存中,重启之后就会丢失,所以,考虑使用外部持久化方案
2.在Nacos 中创建规则,Nacos 会推送到客户端,Sentinel Dashboard 也会从 Nacos 去获取配置信息(远程配置中心(e.g. Nacos, ZooKeeper))

4.1sentinel存储在nacos中限流数据结构

[
  {
    "resource": "byResource", # 资源名
    "limitApp": "default", # 流控针对的调用来源
    "grade": 1, # 限流的阈值类型 1 QPS ,0 并发线程数
    "count": 3, # 每1秒中能通过几个请求
    "strategy": 0, # 0 直接限流 1 关联 2 链路
    "controlBehavior": 0, # 控制效果:0 快速失败 1 warm Up 2 排队等待
    "clusterMode": false # 是否集群效果
  }
]

4.2添加依赖

 <!-- Sentinel 使用 Nacos 存储规则 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

4.3在限流资源添加限流规则

/**
     * <h2>在 dashboard 中 "流控规则" 中按照资源名称新增流控规则</h2>
     * */
    @GetMapping("/by-resource")
    @SentinelResource(
            value = "byResource",
            blockHandler = "ButoolHandleBlockException",
            blockHandlerClass = ButoolBlockHandler.class
    )
    public CommonResponse<String> byResource() {
        log.info("coming in rate limit controller by resource");
        return new CommonResponse<>(0, "", "byResource");
    }
package cn.butool.block_handler;
​
import cn.butool.vo.CommonResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
​
/**
 * <h1>自定义通用的限流处理逻辑</h1>
 * */
@Slf4j
public class ButoolBlockHandler {
​
    /**
     * <h2>通用限流处理方法</h2>
     * 这个方法必须是 static 的
     * */
    public static CommonResponse<String> ButoolHandleBlockException(BlockException exception) {
​
        log.error("trigger qinyi block handler: [{}], [{}]",
                JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp());
        return new CommonResponse<>(
                -1,
                "flow rule trigger block exception",
                null
        );
    }
}

4.4在yml文件中添加配置

datasource:
        # 名称任意, 代表数据源
        ds:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: ${spring.application.name}-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: flow
      # 服务启动直接建立心跳连接
      eager: true

5.GeteWay集成Sentinel实现网关限流

5.1最简单、也是常用的测试方式:在网关内硬编码实现对请求的限流

[
​
  {
    "resource": "nacos-client-api",
    "resourceMode": 1, # 规则与resource相绑定
    "count": 1, # 限流阈值
    "Grade": 1, # 限流的阈值类型 1 QPS ,0 并发线程数
    "intervalSec": 60 # 统计范围 60秒内允许1个请求
  }
]

1网关服务添加依赖

<!-- 集成 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>
        <!-- Sentinel 使用 Nacos 存储规则 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

2yml中添加配置

sentinel: # 与nacos属性平齐
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: 192.168.1.11:7777
        clientIp: 192.168.1.7
        port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
  

3sentinel服务端启动命令修改

# 支持网关
nohup java -Dcsp.sentinel.app.type=1 -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=butool-sentinel-gateway -jar /usr/local/sentinel/sentinel-dashboard-1.8.1.jar &

4网关集成配置类

package cn.butool.config;
​
 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 lombok.extern.slf4j.Slf4j;
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.*;
​
/**
 * <h1>Gateway 集成 Sentinel 实现限流</h1>
 * */
@Slf4j
@Configuration
public class SentinelGatewayConfiguration {
​
    /** 视图解析器 */
    private final List<ViewResolver> viewResolvers;
    /** HTTP 请求和响应数据的编解码配置 */
    private final ServerCodecConfigurer serverCodecConfigurer;
​
    /**
     * <h2>构造方法</h2>
     * */
    public SentinelGatewayConfiguration(
            ObjectProvider<List<ViewResolver>> viewResolversProvider,
            ServerCodecConfigurer serverCodecConfigurer
    ) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
​
    /**
     * <h2>限流异常处理器, 限流异常出现时, 执行到这个 handler</h2>
     * */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // 默认会返回错误 message, code 429
        return new SentinelGatewayBlockExceptionHandler(
                this.viewResolvers,
                this.serverCodecConfigurer
        );
    }
​
    /**
     * <h2>限流过滤器, 是 Gateway 全局过滤器, 优先级定义为最高</h2>
     * */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
​
    /**
     *
     * 初始化限流规则
     * */
    @PostConstruct
    public void doInit(){
​
        log.info("--------------------------------------");
        log.info("load sentinel gateway rules (code define)");
        initGatewayRules();
        log.info("--------------------------------------");
    }
    /**
     * 硬编码网关限流规则
     */
    private void initGatewayRules(){
        Set<GatewayFlowRule> rules = new HashSet<>();
​
        GatewayFlowRule rule = new GatewayFlowRule();
        // 指定限流模式, 根据 route_id 做限流, 默认的模式
        rule.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
        // 指定 route_id -> service id
        rule.setResource("e-commerce-nacos-client");
        // 按照 QPS 限流
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 统计窗口和限流阈值
        rule.setIntervalSec(60);
        rule.setCount(3);
​
        rules.add(rule);
​
       
        // 加载到网关中
        GatewayRuleManager.loadRules(rules);
​
       
    }
}
​

4请求指定的服务查看限流情况

 // 指定 route_id -> service id rule.setResource("e-commerce-nacos-client"); 60秒内请求三次以上报下面错误

5自定义返回错误信息

/**
     *
     * 初始化限流规则
     * */
    @PostConstruct
    public void doInit(){
​
        log.info("--------------------------------------");
        log.info("load sentinel gateway rules (code define)");
        initGatewayRules();
        log.info("--------------------------------------");
​
        // 加载自定义限流异常处理器
        initBlockHandler();
    }
​
​
/**
     * <h2>自定义限流异常处理器</h2>
     * */
    private void initBlockHandler() {
​
        // 自定义 BlockRequestHandler
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange,
                                                      Throwable throwable) {
                log.error("------------- trigger gateway sentinel rule -------------");
                Map<String, String> result = new HashMap<>();
                result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
                result.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
                result.put("route", "e-commerce-nacos-client");
                return ServerResponse
                        .status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(result));
            }
        };
        // 设置自定义限流异常处理器
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

6.自定义分组限流

​
    
/**
     * 硬编码网关限流规则
     */
    private void initGatewayRules(){
        Set<GatewayFlowRule> rules = new HashSet<>();
        // 限流分组, Sentinel 先去找规则定义, 再去找规则中定义的分组
        rules.add(
                new GatewayFlowRule("nacos-client-api-1")
                        .setCount(3).setIntervalSec(60)
        );
        rules.add(
                new GatewayFlowRule("nacos-client-api-2")
                        .setCount(1).setIntervalSec(60)
        );
        // 加载到网关中
        GatewayRuleManager.loadRules(rules);
        // 加载限流分组
        initCustomizedApis();
    }
​
   
​
    /**
     * <h2>硬编码网关限流分组</h2>
     * 1. 最大限制 - 演示
     * 2. 具体的分组
     * */
    private void initCustomizedApis() {
​
        Set<ApiDefinition> definitions = new HashSet<>();
​
        // nacos-client-api 组, 最大的限制
        ApiDefinition api = new ApiDefinition("nacos-client-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    // 模糊匹配 /butool/ecommerce-nacos-client/ 及其子路径的所有请求
                    add(new ApiPathPredicateItem()
                            .setPattern("/butool/ecommerce-nacos-client/**")
                            // 根据前缀匹配
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
​
        // nacos-client-api-1 分组
        ApiDefinition api1 = new ApiDefinition("nacos-client-api-1")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem()
                            // 精确匹配 /butool/ecommerce-nacos-client/nacos-client/service-instance
                            .setPattern("/butool/ecommerce-nacos-client/nacos-client/service-instance"));
                }});
​
        // nacos-client-api-2 分组
        ApiDefinition api2 = new ApiDefinition("nacos-client-api-2")
                .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                    add(new ApiPathPredicateItem()
                            // 精确匹配 /butool/ecommerce-nacos-client/nacos-client/project-config
                            .setPattern("/butool/ecommerce-nacos-client" +
                                    "/nacos-client/project-config"));
                }});
​
        definitions.add(api1);
        definitions.add(api2);
​
        // 加载限流分组
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

5.2配置文件的方式编写限流规则

1.yml文件

硬编码工作较多,相对来说比较繁琐;熟悉之后可以进一步使用配置文件的形式
1.resources目录下存放文件
2.yml文件中配置
    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: 192.168.1.11:7777
        clientIp: 192.168.1.7
        port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      datasource:
       #通过本地文件方式, 基于服务级别的配置
        dsl.file:
          file: classpath:gateway-flow-rule-sentinel.json
          # 代表服务级别的限流, 一步步点进去看, 文件类型
          ruleType: gw-flow
        # 通过本地文件方式, 细粒度对指定 api 进行配置
        ds2.file:
          file: classpath:gateway-flow-rule-api-sentinel.json
          # 代表 API 分组, 一步步点进去看, 文件类型
          ruleType: gw-api-group  

2.json文件

## 文件名 gateway-flow-rule-api-sentinel.json
[
  {
    "apiName": "nacos-client-api",
    "predicateItems": [
      {
        "pattern": "/butool/ecommerce-nacos-client/nacos-client/project-config"
      },
      {
        "pattern": "/butool/ecommerce-nacos-client/**",
        "matchStrategy": 1
      }
    ]
  }
]
​
## 文件名 gateway-flow-rule-sentinel.json
[
  {
    "resource": "e-commerce-nacos-client",
    "resourceMode": 0,
    "count": 3,
    "intervalSec": 60
  },
  {
    "resource": "nacos-client-api",
    "resourceMode": 1,
    "count": 1,
    "intervalSec": 60
  }
]
​

5.配置类

package cn.butool.config;
​
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 lombok.extern.slf4j.Slf4j;
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.*;
​
/**
 * <h1>Gateway 集成 Sentinel 实现限流</h1>
 * */
@Slf4j
@Configuration
public class SentinelGatewayConfiguration {
​
    /** 视图解析器 */
    private final List<ViewResolver> viewResolvers;
    /** HTTP 请求和响应数据的编解码配置 */
    private final ServerCodecConfigurer serverCodecConfigurer;
​
    /**
     * <h2>构造方法</h2>
     * */
    public SentinelGatewayConfiguration(
            ObjectProvider<List<ViewResolver>> viewResolversProvider,
            ServerCodecConfigurer serverCodecConfigurer
    ) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
​
    /**
     * <h2>限流异常处理器, 限流异常出现时, 执行到这个 handler</h2>
     * */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // 默认会返回错误 message, code 429
        return new SentinelGatewayBlockExceptionHandler(
                this.viewResolvers,
                this.serverCodecConfigurer
        );
    }
​
    /**
     * <h2>限流过滤器, 是 Gateway 全局过滤器, 优先级定义为最高</h2>
     * */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}

5.3Gateway集成Nacos+Sentiel实现网关动态限流

1.nacos中添加配置

2.json内容

## dataId gateway-flow-rule-api-sentinel
[
  {
    "apiName": "nacos-client-api",
    "predicateItems": [
      {
        "pattern": "/butool/ecommerce-nacos-client/nacos-client/project-config"
      },
      {
        "pattern": "/butool/ecommerce-nacos-client/**",
        "matchStrategy": 1
      }
    ]
  }
]
​
## dataId gateway-flow-rule-sentinel
[
  {
    "resource": "e-commerce-nacos-client",
    "resourceMode": 0,
    "count": 3,
    "intervalSec": 60
  },
  {
    "resource": "nacos-client-api",
    "resourceMode": 1,
    "count": 1,
    "intervalSec": 60
  }
]

6.为什么需要限流

1.平台用户增长过快 
​2.热点事件、热点接口、热点 Key ​ 
3.恶意请求
​

1.实现原理

Sentinel 通过实现 Filter,对路由/API分组匹配、请求属性解析和参数组装实现限流

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值