美文网首页
改造Sentinel Dashboard规则存储到Nacos

改造Sentinel Dashboard规则存储到Nacos

作者: 猪猪学上树 | 来源:发表于2021-02-20 17:21 被阅读0次

    基于Sentinel Dashboard1.8.0版本改造Nacos存储规则

    代码实现

    下面直接来看看如何实现的具体改造步骤,这里参考了Sentinel Dashboard源码中关于Nacos实现的测试用例。

    第一步:修改pom.xml中的sentinel-datasource-nacos的依赖,将test删除,这样才能在主程序中使用。

    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    

    第二步:前端资源修改

    前端资源修改
    1. 找到resources/app/scripts/controllers/identity.js中的这段代码:
    if (data.code === 0) {
      flowRuleDialog.close();
      let url = '/dashboard/flow/' + $scope.app;
      $location.path(url);
    } else {
      alert('失败:' + data.msg);
    }
    

    修改为:

    if (data.code === 0) {
      flowRuleDialog.close();
      let url = '/dashboard/v2/flow/' + $scope.app;
      $location.path(url);
    } else {
      alert('失败:' + data.msg);
    }
    
    1. 找到resources/app/scripts/directives/sidebar/sidebar.html中的这段代码:
    <li ui-sref-active="active">
        <a ui-sref="dashboard.flowV1({app: entry.app})">
            <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则
        </a>
    </li>
    

    修改为:

    <li ui-sref-active="active">
        <a ui-sref="dashboard.flow({app: entry.app})">
            <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则
        </a>
    </li>
    
    1. 找到resources/app/scripts/services/flow_service_v1.js中的这段代码:
    return $http({
      url: '/v1/flow/rule',
      data: rule,
      method: 'POST'
    });
    

    修改为:

    return $http({
      url: '/v2/flow/rule',
      data: rule,
      method: 'POST'
    });
    
    1. 找到resources/app/views/flow_v2.html中的这段代码:
    <a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})">
      回到单机页面
    </a>
    

    修改为:

    <!--<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})">
      回到单机页面
    </a>-->
    
    1. 重新构建静态资源文件

      进入webapp/resources目录,执行:npm run build命令,推荐使用Node 11.x版本,Node12版本构建会报错

    第三步:在com.alibaba.csp.sentinel.dashboard.rule包下新建一个nacos包,用来编写针对Nacos的扩展实现,新建文件截图如下:

    Nacos扩展实现

    具体代码如下:

    @Component("authorityRuleNacosProvider")
    public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<AuthorityRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
                    AuthorityRuleEntity.class
            );
        }
    }
    
    @Component("authorityRuleNacosPublisher")
    public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<AuthorityRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    @Component("degradeRuleNacosProvider")
    public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<DegradeRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
                    DegradeRuleEntity.class
            );
        }
    }
    
    @Component("degradeRuleNacosPublisher")
    public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
                    rules
            );
        }
    
    @Component("flowRuleNacosProvider")
    public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<FlowRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                    FlowRuleEntity.class
            );
        }
    }
    
    @Component("flowRuleNacosPublisher")
    public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    public class GatewatParamFlowRule extends ParamFlowRule {
        private long intervalSec = 1;
        private GatewayParamFlowItemEntity paramItem;
    
        public long getIntervalSec() {
            return intervalSec;
        }
    
        public void setIntervalSec(long intervalSec) {
            this.intervalSec = intervalSec;
        }
    
        public GatewayParamFlowItemEntity getParamItem() {
            return paramItem;
        }
    
        public void setParamItem(GatewayParamFlowItemEntity paramItem) {
            this.paramItem = paramItem;
        }
    
        @Override
        public String toString() {
            return "ParamFlowRule{" +
                    "grade=" + super.getGrade() +
                    ", paramIdx=" + super.getParamIdx() +
                    ", count=" + super.getCount() +
                    ", controlBehavior=" + super.getControlBehavior() +
                    ", maxQueueingTimeMs=" + super.getMaxQueueingTimeMs() +
                    ", burstCount=" + super.getBurstCount() +
                    ", durationInSec=" + super.getDurationInSec() +
                    ", paramFlowItemList=" + super.getParamFlowItemList() +
                    ", clusterMode=" + super.isClusterMode() +
                    ", clusterConfig=" + super.getClusterConfig() +
                    ", paramItem=" + paramItem +
                    ", intervalSec=" + intervalSec +
                    '}';
        }
    
    }
    
    @Component("gatewayApiRuleNacosProvider")
    public class GatewayApiRuleNacosProvider implements DynamicRuleProvider<List<ApiDefinitionEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<ApiDefinitionEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
                    ApiDefinitionEntity.class
            );
        }
    }
    
    @Component("gatewayApiRuleNacosPublisher")
    public class GatewayApiRuleNacosPublisher implements DynamicRulePublisher<List<ApiDefinitionEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<ApiDefinitionEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    @Component("gatewayFlowRuleNacosProvider")
    public class GatewayFlowRuleNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
                    GatewayFlowRuleEntity.class
            );
        }
    }
    
    @Component("gatewayFlowRuleNacosPublisher")
    public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {
    
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    @Component("paramFlowRuleNacosProvider")
    public class ParamFlowRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<ParamFlowRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
                    ParamFlowRuleEntity.class
            );
        }
    }
    
    @Component("paramFlowRuleNacosPublisher")
    public class ParamFlowRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
    
        @Override
        public void publish(String app, List<ParamFlowRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    @Component("systemRuleNacosProvider")
    public class SystemRuleNacosProvider implements DynamicRuleProvider<List<SystemRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public List<SystemRuleEntity> getRules(String appName) throws Exception {
            return nacosConfigUtil.getRuleEntitiesFromNacos(
                    this.configService,
                    appName,
                    NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
                    SystemRuleEntity.class
            );
        }
    }
    
    @Component("systemRuleNacosPublisher")
    public class SystemRuleNacosPublisher implements DynamicRulePublisher<List<SystemRuleEntity>> {
        @Autowired
        private ConfigService configService;
    
        @Autowired
        private NacosConfigUtil nacosConfigUtil;
    
        @Override
        public void publish(String app, List<SystemRuleEntity> rules) throws Exception {
            nacosConfigUtil.setRuleStringToNacos(
                    this.configService,
                    app,
                    NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
                    rules
            );
        }
    }
    
    @Configuration
    public class NacosConfig {
    
        @Bean
        public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
            return JSON::toJSONString;
        }
    
        @Bean
        public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
            return s -> JSON.parseArray(s, FlowRuleEntity.class);
        }
    
        @Bean
        public ConfigService nacosConfigService() throws Exception {
            NacosProperties nacosProperties = nacosProperties();
            Properties properties = new Properties();
            properties.put(PropertyKeyConst.SERVER_ADDR, nacosProperties.getServerAddr());
            if (StringUtils.isNotBlank(nacosProperties.getNamespace())) {
                properties.put(PropertyKeyConst.NAMESPACE, nacosProperties.getNamespace());
            }
            return ConfigFactory.createConfigService(properties);
        }
    
        @Bean
        @ConfigurationProperties(prefix = "spring.cloud.sentinel.datasource.nacos")
        public NacosProperties nacosProperties() {
            return new NacosProperties();
        }
    
        public static class NacosProperties {
            private String serverAddr;
            private String namespace;
            private String groupId;
    
            // Getter/Setter方法
        }
    }
    
    @Component
    public class NacosConfigUtil {
        @Autowired
        private NacosConfig.NacosProperties nacosProperties;
    
        public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
        public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
        public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";
        public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-flow-rules";
        public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
        public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-flow-rules";
        public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gateway-api-rules";
        public static final String DASHBOARD_POSTFIX = "-dashboard";
        public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";
    
        /**
         * cc for `cluster-client`
         */
        public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";
        /**
         * cs for `cluster-server`
         */
        public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";
        public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";
        public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";
    
        /**
         * 将规则序列化成JSON文本,存储到Nacos server中
         *
         * @param configService nacos config service
         * @param app           应用名称
         * @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
         * @param rules         规则对象
         * @throws NacosException 异常
         */
        public <T> void setRuleStringToNacos(ConfigService configService, String app, String postfix, List<T> rules) throws NacosException {
            AssertUtil.notEmpty(app, "app name cannot be empty");
            if (rules == null) {
                return;
            }
    
            List<Rule> ruleForApp = rules.stream()
                    .map(rule -> {
                        RuleEntity rule1 = (RuleEntity) rule;
                        //System.out.println(rule1.getClass());
                        Rule rule2 = rule1.toRule();
                        //System.out.println(rule2.getClass());
                        return rule2;
                    })
                    .collect(Collectors.toList());
    
            // 存储,给微服务使用
            String dataId = genDataId(app, postfix);
            configService.publishConfig(
                    dataId,
                    nacosProperties.getGroupId(),
                    JSON.toJSONString(ruleForApp)
            );
    
            // 存储,给控制台使用
            configService.publishConfig(
                    dataId + DASHBOARD_POSTFIX,
                    nacosProperties.getGroupId(),
                    JSON.toJSONString(rules,true)
            );
        }
    
        /**
         * 从Nacos server中查询响应规则,并将其反序列化成对应Rule实体
         *
         * @param configService nacos config service
         * @param appName       应用名称
         * @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
         * @param clazz         类
         * @param <T>           泛型
         * @return 规则对象列表
         * @throws NacosException 异常
         */
        public <T> List<T> getRuleEntitiesFromNacos(ConfigService configService, String appName, String postfix, Class<T> clazz) throws NacosException {
            String rules = configService.getConfig(
                    genDataId(appName, postfix) + DASHBOARD_POSTFIX,
                    //genDataId(appName, postfix),
                    nacosProperties.getGroupId(),
                    3000
            );
            if (StringUtil.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return JSON.parseArray(rules,clazz);
        }
    
        private static String genDataId(String appName, String postfix) {
            return appName + postfix;
        }
    }
    

    第四步:规则存储采用Nacos实现,代码修改如下:

    修改为Nacos存储规则
    1. 修改FlowControllerV2.java文件中的DynamicRuleProviderDynamicRulePublisher注入的Bean,改为上面我们编写的针对Nacos的实现:
    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    
    1. 修改GatewayApiController.java、GatewayFlowRuleController.java、AuthorityRuleController.java、DegradeController.java、ParamFlowRuleController.java、SystemController.java文件中的private SentinelApiClient sentinelApiClient;替换成上面我们编写的针对Nacos的实现:

      @Autowired
      @Qualifier("gatewayApiRuleNacosProvider")
      private DynamicRuleProvider<List<ApiDefinitionEntity>> ruleProvider;
      @Autowired
      @Qualifier("gatewayApiRuleNacosPublisher")
      private DynamicRulePublisher<List<ApiDefinitionEntity>> rulePublisher;
      
      @GetMapping("/list.json")
      @AuthAction(AuthService.PrivilegeType.READ_RULE)
      public Result<List<ApiDefinitionEntity>> queryApis(String app, String ip, Integer port) {
      
          if (StringUtil.isEmpty(app)) {
              return Result.ofFail(-1, "app can't be null or empty");
          }
          if (StringUtil.isEmpty(ip)) {
              return Result.ofFail(-1, "ip can't be null or empty");
          }
          if (port == null) {
              return Result.ofFail(-1, "port can't be null");
          }
      
          try {
              List<ApiDefinitionEntity> apis = ruleProvider.getRules(app);
              repository.saveAll(apis);
              return Result.ofSuccess(apis);
          } catch (Throwable throwable) {
              logger.error("queryApis error:", throwable);
              return Result.ofThrowable(-1, throwable);
          }
      }
      
      private boolean publishRules(String app, String ip, Integer port) throws Exception {
          List<ApiDefinitionEntity> rules = repository.findAllByApp(app);
          rulePublisher.publish(app, rules);
          return true;
      }
      
    2. 修改GatewayFlowRuleEntity.java文件中的toRule()方法:

    @Override
    public Rule toRule() {
        GatewatParamFlowRule paramFlowRule = new GatewatParamFlowRule();
        paramFlowRule.setResource(this.getResource());
        paramFlowRule.setCount(this.getCount());
        paramFlowRule.setGrade(this.getGrade());
        paramFlowRule.setDurationInSec(calIntervalSec(this.getInterval(), this.getIntervalUnit()));
        paramFlowRule.setBurstCount(this.getBurst());
        paramFlowRule.setControlBehavior(this.getControlBehavior());
        if (this.getMaxQueueingTimeoutMs() != null) {
            paramFlowRule.setMaxQueueingTimeMs(this.getMaxQueueingTimeoutMs());
        }
    
        //这里需要增加intervalSec参数,GatewayFlowRule需要,否则一直是默认值1
        paramFlowRule.setIntervalSec(paramFlowRule.getDurationInSec());
    
        GatewayParamFlowItemEntity gatewayItem = this.getParamItem();
        paramFlowRule.setParamItem(gatewayItem);
    
        paramFlowRule.setParamIdx(0);
        return paramFlowRule;
    }
    

    第五步:修改application.properties文件,新增Nacos服务相关配置:

    sentinel.dashboard.version=${project.version}
    
    spring.cloud.sentinel.datasource.nacos.server-addr=http://127.0.0.1:8848
    spring.cloud.sentinel.datasource.nacos.groupId=DEFAULT_GROUP
    spring.cloud.sentinel.datasource.nacos.namespace=45fd5650-df52-42ff-92c5-a09516123456
    

    相关文章

      网友评论

          本文标题:改造Sentinel Dashboard规则存储到Nacos

          本文链接:https://www.haomeiwen.com/subject/difxfltx.html