[Spring-Cloud-Alibaba] Sentinel 規則持久化

在以前的練習中,只要應用重啓,就須要從新配置,這樣在咱們實際的項目是很是不實用的,那麼有沒有辦法把咱們配置的規則保存下來呢?答案是YES,那麼接下來,給你們來介紹如何將Sentinel規則持久化。html

Document: 傳送門java

  • File Datasource(文件存儲)git

    • Pull 模式
    • Push 模式
  • Nacos configuration
  • Apollo
File Datasource
Pull 模式
原理:
擴展寫數據源( WritableDataSource), 客戶端主動向某個規則管理中心按期輪詢拉取規則,這個規則中心能夠是 RDBMS、文件 等
pull 模式的數據源(如本地文件、RDBMS 等)通常是可寫入的。使用時須要在客戶端註冊數據源:將對應的讀數據源註冊至對應的 RuleManager,將寫數據源註冊至 transport 的 WritableDataSourceRegistry 中。

過程以下:github

Pull Demo
  • Step 1: 添加配置web

    <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-extension</artifactId>
        </dependency>
  • Step 2: 編寫持久化代碼,實現com.alibaba.csp.sentinel.init.InitFuncspring

    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: 啓用上述代碼json

    resource 目錄下建立 resources/META-INF/services 目錄並建立文件com.alibaba.csp.sentinel.init.InitFunc ,內容爲:緩存

    com.sxzhongf.sharedcenter.configuration.sentinel.datasource.FileDataSourceInit
Pull 優缺點
  • 優勢app

    1. 簡單,無任何依賴
    2. 沒有額外依賴
  • 缺點webapp

    1. 不保證一致性(規則是使用FileRefreshableDataSource定時更新,會有延遲)
    2. 實時性不保證(規則是使用FileRefreshableDataSource定時更新)
    3. 拉取過於頻繁也可能會有性能問題
    4. 因爲文件存儲於本地,容易丟失
  • 參考資料:

    1. ITMUCH
    2. Sentinel WIKI
Push 模式
推薦 經過控制檯設置規則後將規則推送到統一的規則中心,客戶端實現 ReadableDataSource 接口端監聽規則中心實時獲取變動,流程以下:

<img src="https://user-images.githubuse...; width="500" />

  • 實現原理

    1. 控制檯推送規則到Nacos/遠程配置中心
    2. Sentinel client 艦艇Nacos配置變化,更新本地緩存
  • shared_center service 加工

    1. 添加依賴

      <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
    2. 添加配置

      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 查看同步的配置:

相關文章
相關標籤/搜索