欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

[Spring-Cloud-Alibaba] Sentinel 规则持久化

程序员文章站 2022-05-03 22:25:44
在之前的练习中,只要应用重启,就需要重新配置,这样在我们实际的项目是非常不实用的,那么有没有办法把我们配置的规则保存下来呢?答案是YES,那么接下来,给大家来介绍如何将Sentinel规则持久化。 Document: "传送门" File Datasource(文件存储) Pull 模式 Push ......

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

document: 传送门

  • file datasource(文件存储)
    • pull 模式
    • push 模式
  • nacos configuration
  • apollo
file datasource
pull 模式

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

过程如下:
[Spring-Cloud-Alibaba] Sentinel 规则持久化

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接口端监听规则中心实时获取变更,流程如下:

[Spring-Cloud-Alibaba] Sentinel 规则持久化

  • 实现原理

    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 添加流控规则:

    [Spring-Cloud-Alibaba] Sentinel 规则持久化

    nacos 查看同步的配置:

    [Spring-Cloud-Alibaba] Sentinel 规则持久化