改造Sentinel Dashboard规则存储到Nacos

2021-02-20  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读