侧边栏壁纸
博主头像
qingtian博主等级

喜欢是一件细水流长的事,是永不疲惫的双向奔赴~!

  • 累计撰写 104 篇文章
  • 累计创建 48 个标签
  • 累计收到 1 条评论

SpringCloud Alibaba Sentinel使用硬编码方式

qingtian
2022-07-17 / 0 评论 / 0 点赞 / 648 阅读 / 8,318 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-07-17,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

基于 SpringCloud Alibaba Sentinel 实现网关动态限流

SpringCloud Alibaba Sentinel 的概念和来历

  • Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来保证微服务的稳定性

  • 资源:可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其他应用提供的服务,甚至可以是一段代码

    image-20220710100125641

  • 规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则;且所有的规则可以动态的实时调整。

搭建 SpringCloud Alibaba Sentinel 控制台

  • 获取并启动 Sentinel-DashBoard

  • 在官网下载 sentinel-dashboard-1.8.2.jar

  • 启动命令 :

    nohup java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=guank-sentinel-dashboard -jar  ../sentinel-dashboard-1.8.2.jar > sentinel.log &
    
  • 从 Sentinel 1.6.0开始,Sentinel Dashboard 引入了基本的登录功能,默认的用户名密码都是sentinel

Sentinel 控制台的能力

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

Sentinel 的功能及设计理念

  1. 流量控制

    • 服务端需要根据系统的处理能力对流量进行控制,Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。

      image-20220717144550611

  2. Sentinel 流量控制方向

    • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系
    • 运行指标,例如QPS、线程池、系统负载等
    • 控制的效果,例如直接限流、冷启动、排队等

基于硬编码应用Sentinel

  1. 创建e-commerce-sentinel-client

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>ecommerce-springcloud</artifactId>
            <groupId>com.imooc.ecommerce</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>e-commerce-sentinel-client</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <!-- 模块名及描述信息 -->
        <name>e-commerce-sentinel-client</name>
        <description>Sentinel Client</description>
    
        <dependencies>
            <!-- 创建工程需要的两个依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
            <!-- Sentinel 适配了 Feign, 可以实现服务间调用的保护 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!-- Sentinel 使用 Nacos 存储规则 -->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
            </dependency>
            <!-- web 工程 -->
            <dependency>
                <groupId>com.imooc.ecommerce</groupId>
                <artifactId>e-commerce-mvc-config</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <!--
            SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
            SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
         -->
        <build>
            <finalName>${artifactId}</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
  2. 编写 bootstrap.yml

    server:
      port: 8100
      servlet:
        context-path: /ecommerce-sentinel-client
    
    spring:
      application:
        name: e-commerce-sentinel-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时)
      cloud:
        nacos:
          # 服务注册发现
          discovery:
            enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
            server-addr: 192.168.0.103:8848
            #  server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 # Nacos 服务器地址
            namespace: f2dfb4c7-a6cf-45d5-92e2-3912daf808d0
            metadata:
              management:
                context-path: ${server.servlet.context-path}/actuator
        sentinel:
          # 配置 sentinel dashboard 地址
          transport:
            dashboard: 192.168.0.103:7777
            port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
          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
    
    # 暴露端点
    management:
      endpoints:
        web:
          exposure:
            include: '*'
      endpoint:
        health:
          show-details: always
    
    # 打开 Sentinel 对 Feign 的支持
    feign:
      sentinel:
        enabled: true
    
    # 开启或关闭 @SentinelRestTemplate 注解
    resttemplate:
      sentinel:
        enabled: trueserver:
      port: 8100
      servlet:
        context-path: /ecommerce-sentinel-client
    
    spring:
      application:
        name: e-commerce-sentinel-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时)
      cloud:
        nacos:
          # 服务注册发现
          discovery:
            enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可
            server-addr: 192.168.0.103:8848
            #  server-addr: 127.0.0.1:8848,127.0.0.1:8849,127.0.0.1:8850 # Nacos 服务器地址
            namespace: f2dfb4c7-a6cf-45d5-92e2-3912daf808d0
            metadata:
              management:
                context-path: ${server.servlet.context-path}/actuator
        sentinel:
          # 配置 sentinel dashboard 地址
          transport:
            dashboard: 192.168.0.103:7777
            port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
          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
    
    # 暴露端点
    management:
      endpoints:
        web:
          exposure:
            include: '*'
      endpoint:
        health:
          show-details: always
    
    # 打开 Sentinel 对 Feign 的支持
    feign:
      sentinel:
        enabled: true
    
    # 开启或关闭 @SentinelRestTemplate 注解
    resttemplate:
      sentinel:
        enabled: true
    
  3. 编码实例

    /**
     * @author Guank
     * @version 1.0
     * @description: 限流规则硬编码的 controller
     * @date 2022-07-17 15:09
     */
    @Slf4j
    @RestController
    @RequestMapping("/code")
    public class FlowRuleCodeController {
    
        /**
         * 初始化流控规则
         */
        @PostConstruct
        public void init() {
    
            //流控规则集合
            List<FlowRule> flowRules = new ArrayList<>();
            //创建流控规则
            FlowRule flowRule = new FlowRule();
            //设置流控规则 QPS ,限流阈值类型(QPS,并发线程数)
            flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
            //流量控制手段 默认是直接抛弃
            flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
            //设置受保护的资源
            flowRule.setResource("flowRuleCode");
            //设置受保护的资源的阈值 QPS = 1
            flowRule.setCount(1);
            flowRules.add(flowRule);
    
            //加载配置好的流控规则
            FlowRuleManager.loadRules(flowRules);
        }
        /**
         * 使用硬编码的限流规则
         * @return
         */
        @GetMapping("/flow-rule")
        @SentinelResource(value = "flowRuleCode")
        public CommonResponse<String> flowRuleCode() {
            log.info("request flowRuleCode");
            return new CommonResponse<>(0,"","imooc-guank-commerce");
        }
    }
    
  4. snetinel-dashboard中配置规则

    image-20220717153446921

    新增流控规则

  5. 在资源被Sentinel流控后,处理的兜底方法

    /**
     * 当限流异常抛出时,指定调用的方法 兜底策略
     * @param exception
     * @return
     */
    public CommonResponse<String> handleException(BlockException exception) {
        log.error("has block exception : [{}]", JSON.toJSONString(exception.getRule()),exception);
        return new CommonResponse<>(-1,
                "flow rule exception",
                exception.getClass().getCanonicalName());
    }
    ---------------------------------------------------------------------------------------------
    /**
         * 使用硬编码的限流规则
         * @return
         */
        @GetMapping("/flow-rule")
    //    @SentinelResource(value = "flowRuleCode")
        @SentinelResource(value = "flowRuleCode",blockHandler = "handleException")
        public CommonResponse<String> flowRuleCode() {
            log.info("request flowRuleCode");
            return new CommonResponse<>(0,"","imooc-guank-commerce");
        }
    

    注意:处理流控规则的兜底方法必须和流控限制的资源在同一个类里才会被扫描到,否则将不会被扫描到

    返回值也需要和原来的方法一样

  6. 将兜底处理方法放到单独的类里

    /**
     * @author Guank
     * @version 1.0
     * @description: 自定义通用的限流处理逻辑
     * @date 2022-07-17 16:12
     */
    @Slf4j
    public class GuankBlockHandler {
    
        /**
         * 通用限流处理方法
         * 这个方法必须是 static 的
         * @param exception
         * @return
         */
        public static CommonResponse<String> guankHandlerBlockException(BlockException exception) {
            log.error("trigger guank block handler : [{}], [{}]",
                    JSON.toJSONString(exception.getRule()),exception.getRuleLimitApp());
            return new CommonResponse<>(-1,
                    "flow rule trigger block exception",
                    null);
        }
    }
    
    
  7. 在被限流的资源上编辑

    /**
         * 使用硬编码的限流规则
         * @return
         */
        @GetMapping("/flow-rule")
    //    @SentinelResource(value = "flowRuleCode")
    //    @SentinelResource(value = "flowRuleCode",blockHandler = "handleException")
        @SentinelResource(value = "flowRuleCode", blockHandler = "guankHandlerBlockException", blockHandlerClass = {GuankBlockHandler.class})
        public CommonResponse<String> flowRuleCode() {
            log.info("request flowRuleCode");
            return new CommonResponse<>(0,"","imooc-guank-commerce");
        }
    
0

评论区