zoukankan      html  css  js  c++  java
  • [Spring-Cloud-Alibaba] Sentinel 规则持久化

    在之前的练习中,只要应用重启,就需要重新配置,这样在我们实际的项目是非常不实用的,那么有没有办法把我们配置的规则保存下来呢?答案是YES,那么接下来,给大家来介绍如何将Sentinel规则持久化。

    Document: 传送门

    • File Datasource(文件存储)
      • Pull 模式
      • Push 模式
    • Nacos configuration
    • Apollo
    File Datasource
    Pull 模式

    原理:
    扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等
    pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中。

    过程如下:

    Pull Demo
    • Step 1: 添加配置

          <dependency>
              <groupId>com.alibaba.csp</groupId>
              <artifactId>sentinel-datasource-extension</artifactId>
          </dependency>
      
    • Step 2: 编写持久化代码,实现com.alibaba.csp.sentinel.init.InitFunc

      import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
      import com.alibaba.csp.sentinel.datasource.*;
      import com.alibaba.csp.sentinel.init.InitFunc;
      import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
      import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
      import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
      import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
      import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
      import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
      import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
      import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
      import com.alibaba.csp.sentinel.slots.system.SystemRule;
      import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
      import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.TypeReference;
      
      import java.io.File;
      import java.io.IOException;
      import java.util.List;
      
      /**
       * FileDataSourceInit for : 自定义Sentinel存储文件数据源加载类
       *
       * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
       * @since 2019/7/21
       */
      public class FileDataSourceInit implements InitFunc {
          @Override
          public void init() throws Exception {
              // TIPS: 如果你对这个路径不喜欢,可修改为你喜欢的路径
              String ruleDir = System.getProperty("user.home") + "/sentinel/rules";
              String flowRulePath = ruleDir + "/flow-rule.json";
              String degradeRulePath = ruleDir + "/degrade-rule.json";
              String systemRulePath = ruleDir + "/system-rule.json";
              String authorityRulePath = ruleDir + "/authority-rule.json";
              String hotParamFlowRulePath = ruleDir + "/param-flow-rule.json";
      
              this.mkdirIfNotExits(ruleDir);
              this.createFileIfNotExits(flowRulePath);
              this.createFileIfNotExits(degradeRulePath);
              this.createFileIfNotExits(systemRulePath);
              this.createFileIfNotExits(authorityRulePath);
              this.createFileIfNotExits(hotParamFlowRulePath);
              // 流控规则
              ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(
                      flowRulePath,
                      flowRuleListParser
              );
              // 将可读数据源注册至FlowRuleManager
              // 这样当规则文件发生变化时,就会更新规则到内存
              FlowRuleManager.register2Property(flowRuleRDS.getProperty());
              WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
                      flowRulePath,
                      this::encodeJson
              );
              // 将可写数据源注册至transport模块的WritableDataSourceRegistry中
              // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
              WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
      
              // 降级规则
              ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
                      degradeRulePath,
                      degradeRuleListParser
              );
              DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
              WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
                      degradeRulePath,
                      this::encodeJson
              );
              WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
      
              // 系统规则
              ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
                      systemRulePath,
                      systemRuleListParser
              );
              SystemRuleManager.register2Property(systemRuleRDS.getProperty());
              WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
                      systemRulePath,
                      this::encodeJson
              );
              WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
      
              // 授权规则
              ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
                      flowRulePath,
                      authorityRuleListParser
              );
              AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
              WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                      authorityRulePath,
                      this::encodeJson
              );
              WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
      
              // 热点参数规则
              ReadableDataSource<String, List<ParamFlowRule>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>(
                      hotParamFlowRulePath,
                      hotParamFlowRuleListParser
              );
              ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty());
              WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
                      hotParamFlowRulePath,
                      this::encodeJson
              );
              ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
          }
      
          /**
           * 流控规则对象转换
           */
          private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
                  source,
                  new TypeReference<List<FlowRule>>() {
                  }
          );
          /**
           * 降级规则对象转换
           */
          private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
                  source,
                  new TypeReference<List<DegradeRule>>() {
                  }
          );
          /**
           * 系统规则对象转换
           */
          private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
                  source,
                  new TypeReference<List<SystemRule>>() {
                  }
          );
      
          /**
           * 授权规则对象转换
           */
          private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
                  source,
                  new TypeReference<List<AuthorityRule>>() {
                  }
          );
      
          /**
           * 热点规则对象转换
           */
          private Converter<String, List<ParamFlowRule>> hotParamFlowRuleListParser = source -> JSON.parseObject(
                  source,
                  new TypeReference<List<ParamFlowRule>>() {
                  }
          );
      
          /**
           * 创建目录
           *
           * @param filePath
           */
          private void mkdirIfNotExits(String filePath) {
              File file = new File(filePath);
              if (!file.exists()) {
                  file.mkdirs();
              }
          }
      
          /**
           * 创建文件
           *
           * @param filePath
           * @throws IOException
           */
          private void createFileIfNotExits(String filePath) throws IOException {
              File file = new File(filePath);
              if (!file.exists()) {
                  file.createNewFile();
              }
          }
      
          private <T> String encodeJson(T t) {
              return JSON.toJSONString(t);
          }
      }
      
    • Step 3: 启用上述代码

      resource 目录下创建 resources/META-INF/services 目录并创建文件com.alibaba.csp.sentinel.init.InitFunc ,内容为:

      com.sxzhongf.sharedcenter.configuration.sentinel.datasource.FileDataSourceInit
      
    Pull 优缺点
    • 优点
      1. 简单,无任何依赖
      2. 没有额外依赖
    • 缺点
      1. 不保证一致性(规则是使用FileRefreshableDataSource定时更新,会有延迟)
      2. 实时性不保证(规则是使用FileRefreshableDataSource定时更新)
      3. 拉取过于频繁也可能会有性能问题
      4. 由于文件存储于本地,容易丢失
    • 参考资料:
      1. ITMUCH
      2. Sentinel WIKI
    Push 模式

    推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource接口端监听规则中心实时获取变更,流程如下:

    • 实现原理

      1. 控制台推送规则到Nacos/远程配置中心
      2. Sentinel client 舰艇Nacos配置变化,更新本地缓存
    • shared_center service 加工

      1. 添加依赖
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
      
      1. 添加配置
      spring:
        cloud:
          sentinel:
            datasource:
              sxzhongf_flow:
                nacos:
                  server-addr: localhost:8848
                  dataId: ${spring.application.name}-flow-rules
                  groupId: SENTINEL_GROUP
                  # 规则类型,取值见:org.springframework.cloud.alibaba.sentinel.datasource.RuleType
                  rule_type: flow
              sxzhongf_degrade:
                nacos:
                  server-addr: localhost:8848
                  dataId: ${spring.application.name}-degrade-rules
                  groupId: SENTINEL_GROUP
                  rule-type: degrade
      
    • Sentinel dashboard 加工

      Dashboard 规则改造主要通过2个接口:

      com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider & com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher

      • Download Sentinel Source Code

      • 修改原sentinel-dashboard项目下的POM文件

            <!-- for Nacos rule publisher sample -->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
                <!--注释掉原文件中的scope,让其不仅在test的时候生效-->
                <!--<scope>test</scope>-->
            </dependency>
        
      • 偷懒模式:复制sentinel-dashboard项目下test下的nacos包(

        src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacossrc/main/java/com/alibaba/csp/sentinel/dashboard/rule

      • 修改controller中的默认provider & publisher

        com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2

            @Autowired
            // @Qualifier("flowRuleDefaultProvider")
        		@Qualifier("flowRuleNacosProvider")
            private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
            @Autowired
        		// @Qualifier("flowRuleDefaultPublisher")
            @Qualifier("flowRuleNacosPublisher")
            private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
        
      • 打开 /Sentinel-1.6.2/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html文件,修改代码:

        <!--<li ui-sref-active="active">-->
                    <!--<a ui-sref="dashboard.flow({app: entry.app})">-->
                      <!--<i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则 V1</a>-->
        <!--</li>-->
        
        ---
        
        改为
        
          <li ui-sref-active="active">
            <a ui-sref="dashboard.flow({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;NACOS 流控规则 V1</a>
          </li>
        

      Dashboard中要修改的代码已经好了。

    • 重新启动 Sentinel-dashboard mvn clean package -DskipTests

    • 测试效果

      Sentinel 添加流控规则:

      Nacos 查看同步的配置:


  • 相关阅读:
    学习python -- 第013天 类与对象
    学习python -- 第013天 bug
    学习python -- 第012天 函数(二)
    学习python -- 第012天 函数(一)
    学习python -- 第011天 字符串
    学习python -- 第010天 列表、元组、字典、集合总结
    排序_快速排序
    链表_逆置
    约瑟夫环-链表
    双栈_队列
  • 原文地址:https://www.cnblogs.com/zhangpan1244/p/11228020.html
Copyright © 2011-2022 走看看