• Sentinel dashboard规则持久化到nacos改造


    Sentinel dashboard规则持久化到nacos改造

    前言

    官方提供的Dashboard源码包含前端html代码及后端逻辑处理,后端采用SpringBoot工程构建,暴露Controller给前端页面访问。

    改造

    后端改造点总结如下:

    1. 添加nacos数据源依赖;
    2. 实现基于nacos的规则对象的存取,其中存储需要实现DynamicRulePublisher接口,获取需要实现DynamicRuleProvider接口;
    3. 修改提供接口服务的Controller,使其使用新的nacos存取类,调用相关方法与nacos交互,实现规则持久化到nacos的功能

    前端改造点总结:

    修改sidebar.html页面指向FlowControllerV2

    注:nacos数据源的存取,可参考test模块com.alibaba.csp.sentinel.dashboard.rule.nacos的FlowRuleNacosProvider和FlowRuleNacosPublisher

    代码改造后整体预览:

    添加依赖

    修改sentinel-dashboard下pom.xml找到 如下依赖 把test注释掉

            
            <dependency>
                <groupId>com.alibaba.cspgroupId>
                <artifactId>sentinel-datasource-nacosartifactId>
    
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    实现nacos配置

    找到

    sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos

    目录,将整个目录拷贝到

    sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos

    image-20220918165742470

    然后修改为(直接基于下面内容新建即可):

    NacosConfig

    读取nacos相关配置,注入ConfigService类

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.nacos.api.PropertyKeyConst;
    import com.alibaba.nacos.api.config.ConfigFactory;
    import com.alibaba.nacos.api.config.ConfigService;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Properties;
    
    /**
     * @author Eric Zhao
     * @since 1.4.0
     */
    @Configuration
    public class NacosConfig {
    
        @Value("${nacos.address}")
        private String address;
    
        @Value("${nacos.namespace:}")
        private String namespace;
    
        @Bean
        public ConfigService nacosConfigService() throws Exception {
            Properties properties = new Properties();
            // nacos集群地址
            properties.put(PropertyKeyConst.SERVER_ADDR, address);
            // namespace为空即为public
            properties.put(PropertyKeyConst.NAMESPACE, namespace);
            return ConfigFactory.createConfigService(properties);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    application.properties

    新增nacos地址及namespace配置

    # nacos配置
    nacos.address=localhost:8848
    nacos.namespace=sentinel
    
    • 1
    • 2
    • 3
    NacosConfigUtil

    nacos相关共用后缀及转换工具类

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @since 1.4.0
     */
    public final class NacosConfigUtil {
    
        public static final String GROUP_ID = "SENTINEL_GROUP";
    
        public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
        public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";
        public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";
        public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
        public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";
        public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
        public static final String DASHBOARD_POSTFIX = "-dashboard";
    
        /**
         * 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";
    
        private NacosConfigUtil() {
        }
    
        public static String toJSONString(Object obj) {
            return JSON.toJSONString(obj, SerializerFeature.PrettyFormat);
        }
    
        public static <T> List<T> parseList(String text, Class<T> clazz) {
            return JSON.parseArray(text, clazz);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    NacosService

    统一nacos服务,供provider和publisher复用

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.csp.sentinel.util.AssertUtil;
    import com.alibaba.csp.sentinel.util.StringUtil;
    import com.alibaba.nacos.api.config.ConfigService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 自定义nacos服务类
     *
     * @author liuyang
     * 创建时间: 2022-09-14 16:48
     */
    @Component
    public class NacosService {
    
        @Autowired
        private ConfigService configService;
    
        public <T> List<T> getRules(String dataId, Class<T> clazz) throws Exception {
            String rules = configService.getConfig(dataId, NacosConfigUtil.GROUP_ID, 3000);
            if (StringUtil.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return NacosConfigUtil.parseList(rules, clazz);
        }
    
        public void publish(String dataId, Object rules) throws Exception {
            AssertUtil.notEmpty(dataId, "app name cannot be empty");
            if (rules == null) {
                return;
            }
            configService.publishConfig(dataId, NacosConfigUtil.GROUP_ID, NacosConfigUtil.toJSONString(rules));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    流控改造(flow)

    com.alibaba.csp.sentinel.dashboard.rule.nacos.flow下新建FlowRuleNacosProvider和FlowRuleNacosPublisher类。

    nacos中配置中心中dataId为 {appName}-flow-rules,group为:SENTINEL_GROUP,如下图:

    文本格式示例:

    [
    	{
    		"app":"feign", // 服务名称
    		"controlBehavior":0, //流控效果,0表示快速失败,1表示Warm Up,2表示排队等待
    		"count":1.0, //阀值
    		"gmtCreate":1663234159319,
    		"gmtModified":1663234159319,
    		"grade":1, //阀值类型,0表示线程数,1表示QPS;
    		"id":3,
    		"ip":"3.0.1.156",
    		"limitApp":"default", //来源应用	
    		"port":8720,
    		"resource":"/api/hello", //资源名称
    		"strategy":0 // 流控模式,0表示直接,1表示关联,2表示链路;
    	}
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    注: 如复制到nacos中新增报错,则删除相关注释文字即可。

    FlowRuleNacosProvider

    app名增加 -flow-rules 后缀存入nacos中

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 流控规则
     * @since 1.4.0
     */
    @Component("flowRuleNacosProvider")
    public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public List<FlowRuleEntity> getRules(String appName) throws Exception {
            return nacosService.getRules(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, FlowRuleEntity.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    FlowRuleNacosPublisher

    app名称增加 -flow-rules 后缀从nacos中获取

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @description 流控规则
     * @author Eric Zhao
     * @since 1.4.0
     */
    @Component("flowRuleNacosPublisher")
    public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
            nacosService.publish(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    FlowControllerV2
        @Autowired
        @Qualifier("flowRuleDefaultProvider")
        private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("flowRuleDefaultPublisher")
        private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    修改为:

        @Autowired
        @Qualifier("flowRuleNacosProvider")
        private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("flowRuleNacosPublisher")
        private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    sidebar.html
              <li ui-sref-active="active" ng-if="!entry.isGateway">
                <a ui-sref="dashboard.flowV1({app: entry.app})">
                  <i class="glyphicon glyphicon-filter">i>  流控规则a>
              li>
    
    • 1
    • 2
    • 3
    • 4

    修改为(把V1去掉):

              <li ui-sref-active="active" ng-if="!entry.isGateway">
                <a ui-sref="dashboard.flow({app: entry.app})">
                  <i class="glyphicon glyphicon-filter">i>  流控规则a>
              li>
    
    • 1
    • 2
    • 3
    • 4

    流控规则改造成推模式持久化完成!

    degrade(熔断降级),system(系统规则),authority(授权规则),param-flow(参数规则) 【根据自己项目实际需要来配置这些规则】依次按照上面的步骤修改。

    熔断降级(degrade)

    DegradeRuleNacosProvider
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 熔断降级
     * @since 1.4.0
     */
    @Component("degradeRuleNacosProvider")
    public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public List<DegradeRuleEntity> getRules(String appName) throws Exception {
            return nacosService.getRules(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, DegradeRuleEntity.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    DegradeRuleNacosPublisher
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 熔断降级
     * @since 1.4.0
     */
    @Component("degradeRuleNacosPublisher")
    public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
            nacosService.publish(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    DegradeController
    package com.alibaba.csp.sentinel.dashboard.controller;
    
    import java.util.Date;
    import java.util.List;
    
    import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
    import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
    import com.alibaba.csp.sentinel.util.StringUtil;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.domain.Result;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * Controller regarding APIs of degrade rules. Refactored since 1.8.0.
     *
     * @author Carpenter Lee
     * @author Eric Zhao
     */
    @RestController
    @RequestMapping("/degrade")
    public class DegradeController {
    
        private final Logger logger = LoggerFactory.getLogger(DegradeController.class);
    
        @Autowired
        private RuleRepository<DegradeRuleEntity, Long> repository;
    
        @Autowired
        @Qualifier("degradeRuleNacosProvider")
        private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("degradeRuleNacosPublisher")
        private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
    //    @Autowired
    //    private SentinelApiClient sentinelApiClient;
    
        @GetMapping("/rules.json")
        @AuthAction(PrivilegeType.READ_RULE)
        public Result<List<DegradeRuleEntity>> apiQueryMachineRules(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 rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
                List<DegradeRuleEntity> rules = ruleProvider.getRules(app);
                rules = repository.saveAll(rules);
                return Result.ofSuccess(rules);
            } catch (Throwable throwable) {
                logger.error("queryApps error:", throwable);
                return Result.ofThrowable(-1, throwable);
            }
        }
    
        @PostMapping("/rule")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<DegradeRuleEntity> apiAddRule(@RequestBody DegradeRuleEntity entity) {
            Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
            Date date = new Date();
            entity.setGmtCreate(date);
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                publishRules(entity.getApp());
            } catch (Throwable t) {
                logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t);
                return Result.ofThrowable(-1, t);
            }
    //        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    //            logger.warn("Publish degrade rules failed, app={}", entity.getApp());
    //        }
            return Result.ofSuccess(entity);
        }
    
        @PutMapping("/rule/{id}")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<DegradeRuleEntity> apiUpdateRule(@PathVariable("id") Long id,
                                                       @RequestBody DegradeRuleEntity entity) {
            if (id == null || id <= 0) {
                return Result.ofFail(-1, "id can't be null or negative");
            }
            DegradeRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofFail(-1, "Degrade rule does not exist, id=" + id);
            }
            entity.setApp(oldEntity.getApp());
            entity.setIp(oldEntity.getIp());
            entity.setPort(oldEntity.getPort());
            entity.setId(oldEntity.getId());
            Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
    
            entity.setGmtCreate(oldEntity.getGmtCreate());
            entity.setGmtModified(new Date());
            try {
                entity = repository.save(entity);
                publishRules(entity.getApp());
            } catch (Throwable t) {
                logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t);
                return Result.ofThrowable(-1, t);
            }
    //        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    //            logger.warn("Publish degrade rules failed, app={}", entity.getApp());
    //        }
            return Result.ofSuccess(entity);
        }
    
        @DeleteMapping("/rule/{id}")
        @AuthAction(PrivilegeType.DELETE_RULE)
        public Result<Long> delete(@PathVariable("id") Long id) {
            if (id == null) {
                return Result.ofFail(-1, "id can't be null");
            }
    
            DegradeRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofSuccess(null);
            }
    
            try {
                repository.delete(id);
                publishRules(oldEntity.getApp());
            } catch (Throwable throwable) {
                logger.error("Failed to delete degrade rule, id={}", id, throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
    //            logger.warn("Publish degrade rules failed, app={}", oldEntity.getApp());
    //        }
            return Result.ofSuccess(id);
        }
    
        //    private boolean publishRules(String app, String ip, Integer port) {
    //        List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    //        return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
    //    }
        private void publishRules(String app) throws Exception {
            List<DegradeRuleEntity> rules = repository.findAllByApp(app);
            rulePublisher.publish(app, rules);
        }
    
        private <R> Result<R> checkEntityInternal(DegradeRuleEntity entity) {
            if (StringUtil.isBlank(entity.getApp())) {
                return Result.ofFail(-1, "app can't be blank");
            }
            if (StringUtil.isBlank(entity.getIp())) {
                return Result.ofFail(-1, "ip can't be null or empty");
            }
            if (entity.getPort() == null || entity.getPort() <= 0) {
                return Result.ofFail(-1, "invalid port: " + entity.getPort());
            }
            if (StringUtil.isBlank(entity.getLimitApp())) {
                return Result.ofFail(-1, "limitApp can't be null or empty");
            }
            if (StringUtil.isBlank(entity.getResource())) {
                return Result.ofFail(-1, "resource can't be null or empty");
            }
            Double threshold = entity.getCount();
            if (threshold == null || threshold < 0) {
                return Result.ofFail(-1, "invalid threshold: " + threshold);
            }
            Integer recoveryTimeoutSec = entity.getTimeWindow();
            if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) {
                return Result.ofFail(-1, "recoveryTimeout should be positive");
            }
            Integer strategy = entity.getGrade();
            if (strategy == null) {
                return Result.ofFail(-1, "circuit breaker strategy cannot be null");
            }
            if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()
                    || strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
                return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy);
            }
            if (entity.getMinRequestAmount() == null || entity.getMinRequestAmount() <= 0) {
                return Result.ofFail(-1, "Invalid minRequestAmount");
            }
            if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) {
                return Result.ofFail(-1, "Invalid statInterval");
            }
            if (strategy == RuleConstant.DEGRADE_GRADE_RT) {
                Double slowRatio = entity.getSlowRatioThreshold();
                if (slowRatio == null) {
                    return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy");
                } else if (slowRatio < 0 || slowRatio > 1) {
                    return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]");
                }
            } else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
                if (threshold > 1) {
                    return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]");
                }
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222

    系统规则(system)

    SystemRuleNacosProvider
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.system;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 系统规则
     * @since 1.4.0
     */
    @Component("systemRuleNacosProvider")
    public class SystemRuleNacosProvider implements DynamicRuleProvider<List<SystemRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public List<SystemRuleEntity> getRules(String appName) throws Exception {
            return nacosService.getRules(appName + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX, SystemRuleEntity.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    SystemRuleNacosPublisher
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.system;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 系统规则
     * @since 1.4.0
     */
    @Component("systemRuleNacosPublisher")
    public class SystemRuleNacosPublisher implements DynamicRulePublisher<List<SystemRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public void publish(String app, List<SystemRuleEntity> rules) throws Exception {
            nacosService.publish(app + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    SystemController
    package com.alibaba.csp.sentinel.dashboard.controller;
    
    import java.util.Date;
    import java.util.List;
    
    import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
    import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.util.StringUtil;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.domain.Result;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author leyou(lihao)
     */
    @RestController
    @RequestMapping("/system")
    public class SystemController {
    
        private final Logger logger = LoggerFactory.getLogger(SystemController.class);
    
        @Autowired
        private RuleRepository<SystemRuleEntity, Long> repository;
        //    @Autowired
    //    private SentinelApiClient sentinelApiClient;
        @Autowired
        @Qualifier("systemRuleNacosProvider")
        private DynamicRuleProvider<List<SystemRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("systemRuleNacosPublisher")
        private DynamicRulePublisher<List<SystemRuleEntity>> rulePublisher;
    
        private <R> Result<R> checkBasicParams(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");
            }
            if (port <= 0 || port > 65535) {
                return Result.ofFail(-1, "port should be in (0, 65535)");
            }
            return null;
        }
    
        @GetMapping("/rules.json")
        @AuthAction(PrivilegeType.READ_RULE)
        public Result<List<SystemRuleEntity>> apiQueryMachineRules(String app, String ip,
                                                                   Integer port) {
            Result<List<SystemRuleEntity>> checkResult = checkBasicParams(app, ip, port);
            if (checkResult != null) {
                return checkResult;
            }
            try {
                //List rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port);
                List<SystemRuleEntity> rules = ruleProvider.getRules(app);
                rules = repository.saveAll(rules);
                return Result.ofSuccess(rules);
            } catch (Throwable throwable) {
                logger.error("Query machine system rules error", throwable);
                return Result.ofThrowable(-1, throwable);
            }
        }
    
        private int countNotNullAndNotNegative(Number... values) {
            int notNullCount = 0;
            for (int i = 0; i < values.length; i++) {
                if (values[i] != null && values[i].doubleValue() >= 0) {
                    notNullCount++;
                }
            }
            return notNullCount;
        }
    
        @RequestMapping("/new.json")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<SystemRuleEntity> apiAdd(String app, String ip, Integer port,
                                               Double highestSystemLoad, Double highestCpuUsage, Long avgRt,
                                               Long maxThread, Double qps) {
    
            Result<SystemRuleEntity> checkResult = checkBasicParams(app, ip, port);
            if (checkResult != null) {
                return checkResult;
            }
    
            int notNullCount = countNotNullAndNotNegative(highestSystemLoad, avgRt, maxThread, qps, highestCpuUsage);
            if (notNullCount != 1) {
                return Result.ofFail(-1, "only one of [highestSystemLoad, avgRt, maxThread, qps,highestCpuUsage] "
                        + "value must be set > 0, but " + notNullCount + " values get");
            }
            if (null != highestCpuUsage && highestCpuUsage > 1) {
                return Result.ofFail(-1, "highestCpuUsage must between [0.0, 1.0]");
            }
            SystemRuleEntity entity = new SystemRuleEntity();
            entity.setApp(app.trim());
            entity.setIp(ip.trim());
            entity.setPort(port);
            // -1 is a fake value
            if (null != highestSystemLoad) {
                entity.setHighestSystemLoad(highestSystemLoad);
            } else {
                entity.setHighestSystemLoad(-1D);
            }
    
            if (null != highestCpuUsage) {
                entity.setHighestCpuUsage(highestCpuUsage);
            } else {
                entity.setHighestCpuUsage(-1D);
            }
    
            if (avgRt != null) {
                entity.setAvgRt(avgRt);
            } else {
                entity.setAvgRt(-1L);
            }
            if (maxThread != null) {
                entity.setMaxThread(maxThread);
            } else {
                entity.setMaxThread(-1L);
            }
            if (qps != null) {
                entity.setQps(qps);
            } else {
                entity.setQps(-1D);
            }
            Date date = new Date();
            entity.setGmtCreate(date);
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                publishRules(app);
            } catch (Throwable throwable) {
                logger.error("Add SystemRule error", throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(app, ip, port)) {
    //            logger.warn("Publish system rules fail after rule add");
    //        }
            return Result.ofSuccess(entity);
        }
    
        @GetMapping("/save.json")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<SystemRuleEntity> apiUpdateIfNotNull(Long id, String app, Double highestSystemLoad,
                                                           Double highestCpuUsage, Long avgRt, Long maxThread, Double qps) {
            if (id == null) {
                return Result.ofFail(-1, "id can't be null");
            }
            SystemRuleEntity entity = repository.findById(id);
            if (entity == null) {
                return Result.ofFail(-1, "id " + id + " dose not exist");
            }
    
            if (StringUtil.isNotBlank(app)) {
                entity.setApp(app.trim());
            }
            if (highestSystemLoad != null) {
                if (highestSystemLoad < 0) {
                    return Result.ofFail(-1, "highestSystemLoad must >= 0");
                }
                entity.setHighestSystemLoad(highestSystemLoad);
            }
            if (highestCpuUsage != null) {
                if (highestCpuUsage < 0) {
                    return Result.ofFail(-1, "highestCpuUsage must >= 0");
                }
                if (highestCpuUsage > 1) {
                    return Result.ofFail(-1, "highestCpuUsage must <= 1");
                }
                entity.setHighestCpuUsage(highestCpuUsage);
            }
            if (avgRt != null) {
                if (avgRt < 0) {
                    return Result.ofFail(-1, "avgRt must >= 0");
                }
                entity.setAvgRt(avgRt);
            }
            if (maxThread != null) {
                if (maxThread < 0) {
                    return Result.ofFail(-1, "maxThread must >= 0");
                }
                entity.setMaxThread(maxThread);
            }
            if (qps != null) {
                if (qps < 0) {
                    return Result.ofFail(-1, "qps must >= 0");
                }
                entity.setQps(qps);
            }
            Date date = new Date();
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                publishRules(entity.getApp());
            } catch (Throwable throwable) {
                logger.error("save error:", throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    //            logger.info("publish system rules fail after rule update");
    //        }
            return Result.ofSuccess(entity);
        }
    
        @RequestMapping("/delete.json")
        @AuthAction(PrivilegeType.DELETE_RULE)
        public Result<?> delete(Long id) {
            if (id == null) {
                return Result.ofFail(-1, "id can't be null");
            }
            SystemRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofSuccess(null);
            }
            try {
                repository.delete(id);
                publishRules(oldEntity.getApp());
            } catch (Throwable throwable) {
                logger.error("delete error:", throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
    //            logger.info("publish system rules fail after rule delete");
    //        }
            return Result.ofSuccess(id);
        }
    
        //    private boolean publishRules(String app, String ip, Integer port) {
    //        List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    //        return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules);
    //    }
        private void publishRules(String app) throws Exception {
            List<SystemRuleEntity> rules = repository.findAllByApp(app);
            rulePublisher.publish(app, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250

    授权规则(authority)

    AuthorityRuleNacosProvider
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.authority;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 授权规则
     * @since 1.4.0
     */
    @Component("authorityRuleNacosProvider")
    public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public List<AuthorityRuleEntity> getRules(String appName) throws Exception {
            return nacosService.getRules(appName + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX, AuthorityRuleEntity.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    AuthorityRuleNacosPublisher
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.authority;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 授权规则
     * @since 1.4.0
     */
    @Component("authorityRuleNacosPublisher")
    public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public void publish(String app, List<AuthorityRuleEntity> rules) throws Exception {
            nacosService.publish(app + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    AuthorityRuleController
    package com.alibaba.csp.sentinel.dashboard.controller;
    
    import java.util.Date;
    import java.util.List;
    
    import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.csp.sentinel.util.StringUtil;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.domain.Result;
    import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author Eric Zhao
     * @since 0.2.1
     */
    @RestController
    @RequestMapping(value = "/authority")
    public class AuthorityRuleController {
    
        private final Logger logger = LoggerFactory.getLogger(AuthorityRuleController.class);
    
        //    @Autowired
    //    private SentinelApiClient sentinelApiClient;
        @Autowired
        @Qualifier("authorityRuleNacosProvider")
        private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("authorityRuleNacosPublisher")
        private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;
    
        @Autowired
        private RuleRepository<AuthorityRuleEntity, Long> repository;
    
        @GetMapping("/rules")
        @AuthAction(PrivilegeType.READ_RULE)
        public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
                                                                            @RequestParam String ip,
                                                                            @RequestParam Integer port) {
            if (StringUtil.isEmpty(app)) {
                return Result.ofFail(-1, "app cannot be null or empty");
            }
            if (StringUtil.isEmpty(ip)) {
                return Result.ofFail(-1, "ip cannot be null or empty");
            }
            if (port == null || port <= 0) {
                return Result.ofFail(-1, "Invalid parameter: port");
            }
            try {
    //            List rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
                List<AuthorityRuleEntity> rules = ruleProvider.getRules(app);
                rules = repository.saveAll(rules);
                return Result.ofSuccess(rules);
            } catch (Throwable throwable) {
                logger.error("Error when querying authority rules", throwable);
                return Result.ofFail(-1, throwable.getMessage());
            }
        }
    
        private <R> Result<R> checkEntityInternal(AuthorityRuleEntity entity) {
            if (entity == null) {
                return Result.ofFail(-1, "bad rule body");
            }
            if (StringUtil.isBlank(entity.getApp())) {
                return Result.ofFail(-1, "app can't be null or empty");
            }
            if (StringUtil.isBlank(entity.getIp())) {
                return Result.ofFail(-1, "ip can't be null or empty");
            }
            if (entity.getPort() == null || entity.getPort() <= 0) {
                return Result.ofFail(-1, "port can't be null");
            }
            if (entity.getRule() == null) {
                return Result.ofFail(-1, "rule can't be null");
            }
            if (StringUtil.isBlank(entity.getResource())) {
                return Result.ofFail(-1, "resource name cannot be null or empty");
            }
            if (StringUtil.isBlank(entity.getLimitApp())) {
                return Result.ofFail(-1, "limitApp should be valid");
            }
            if (entity.getStrategy() != RuleConstant.AUTHORITY_WHITE
                    && entity.getStrategy() != RuleConstant.AUTHORITY_BLACK) {
                return Result.ofFail(-1, "Unknown strategy (must be blacklist or whitelist)");
            }
            return null;
        }
    
        @PostMapping("/rule")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) {
            Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
            entity.setId(null);
            Date date = new Date();
            entity.setGmtCreate(date);
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                publishRules(entity.getApp());
            } catch (Throwable throwable) {
                logger.error("Failed to add authority rule", throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    //            logger.info("Publish authority rules failed after rule add");
    //        }
            return Result.ofSuccess(entity);
        }
    
        @PutMapping("/rule/{id}")
        @AuthAction(PrivilegeType.WRITE_RULE)
        public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
                                                                  @RequestBody AuthorityRuleEntity entity) {
            if (id == null || id <= 0) {
                return Result.ofFail(-1, "Invalid id");
            }
            Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
            entity.setId(id);
            Date date = new Date();
            entity.setGmtCreate(null);
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                if (entity == null) {
                    return Result.ofFail(-1, "Failed to save authority rule");
                }
                publishRules(entity.getApp());
            } catch (Throwable throwable) {
                logger.error("Failed to save authority rule", throwable);
                return Result.ofThrowable(-1, throwable);
            }
    //        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
    //            logger.info("Publish authority rules failed after rule update");
    //        }
            return Result.ofSuccess(entity);
        }
    
        @DeleteMapping("/rule/{id}")
        @AuthAction(PrivilegeType.DELETE_RULE)
        public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
            if (id == null) {
                return Result.ofFail(-1, "id cannot be null");
            }
            AuthorityRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofSuccess(null);
            }
            try {
                repository.delete(id);
                publishRules(oldEntity.getApp());
            } catch (Exception e) {
                return Result.ofFail(-1, e.getMessage());
            }
    //        if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
    //            logger.error("Publish authority rules failed after rule delete");
    //        }
            return Result.ofSuccess(id);
        }
    
        //    private boolean publishRules(String app, String ip, Integer port) {
    //        List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    //        return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
    //    }
        private void publishRules(String app) throws Exception {
            List<AuthorityRuleEntity> rules = repository.findAllByApp(app);
            rulePublisher.publish(app, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192

    参数规则(param-flow )

    ParamFlowRuleNacosProvider
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.param;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 参数规则
     * @since 1.4.0
     */
    @Component("paramFlowRuleNacosProvider")
    public class ParamFlowRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public List<ParamFlowRuleEntity> getRules(String appName) throws Exception {
            return nacosService.getRules(appName + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX, ParamFlowRuleEntity.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    ParamFlowRuleNacosPublisher
    package com.alibaba.csp.sentinel.dashboard.rule.nacos.param;
    
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author Eric Zhao
     * @description 参数规则
     * @since 1.4.0
     */
    @Component("paramFlowRuleNacosPublisher")
    public class ParamFlowRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {
    
        @Autowired
        private NacosService nacosService;
    
        @Override
        public void publish(String app, List<ParamFlowRuleEntity> rules) throws Exception {
            nacosService.publish(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX, rules);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    ParamFlowRuleController
    package com.alibaba.csp.sentinel.dashboard.controller;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Optional;
    import java.util.concurrent.ExecutionException;
    
    import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
    import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException;
    import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
    import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.csp.sentinel.util.StringUtil;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.domain.Result;
    import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
    import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author Eric Zhao
     * @since 0.2.1
     */
    @RestController
    @RequestMapping(value = "/paramFlow")
    public class ParamFlowRuleController {
    
        private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class);
    
        //    @Autowired
    //    private SentinelApiClient sentinelApiClient;
        @Autowired
        @Qualifier("paramFlowRuleNacosProvider")
        private DynamicRuleProvider<List<ParamFlowRuleEntity>> ruleProvider;
        @Autowired
        @Qualifier("paramFlowRuleNacosPublisher")
        private DynamicRulePublisher<List<ParamFlowRuleEntity>> rulePublisher;
        @Autowired
        private AppManagement appManagement;
        @Autowired
        private RuleRepository<ParamFlowRuleEntity, Long> repository;
    
        private boolean checkIfSupported(String app, String ip, int port) {
            try {
                return Optional.ofNullable(appManagement.getDetailApp(app))
                        .flatMap(e -> e.getMachine(ip, port))
                        .flatMap(m -> VersionUtils.parseVersion(m.getVersion())
                                .map(v -> v.greaterOrEqual(version020)))
                        .orElse(true);
                // If error occurred or cannot retrieve machine info, return true.
            } catch (Exception ex) {
                return true;
            }
        }
    
        @GetMapping("/rules")
        @AuthAction(PrivilegeType.READ_RULE)
        public Result<List<ParamFlowRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
                                                                            @RequestParam String ip,
                                                                            @RequestParam Integer port) {
            if (StringUtil.isEmpty(app)) {
                return Result.ofFail(-1, "app cannot be null or empty");
            }
            if (StringUtil.isEmpty(ip)) {
                return Result.ofFail(-1, "ip cannot be null or empty");
            }
            if (port == null || port <= 0) {
                return Result.ofFail(-1, "Invalid parameter: port");
            }
            if (!checkIfSupported(app, ip, port)) {
                return unsupportedVersion();
            }
            try {
    //            return sentinelApiClient.fetchParamFlowRulesOfMachine(app, ip, port)
    //                .thenApply(repository::saveAll)
    //                .thenApply(Result::ofSuccess)
    //                .get();
                List<ParamFlowRuleEntity> rules = ruleProvider.getRules(app);
                rules = repository.saveAll(rules);
                return Result.ofSuccess(rules);
            } catch (ExecutionException ex) {
                logger.error("Error when querying parameter flow rules", ex.getCause());
                if (isNotSupported(ex.getCause())) {
                    return unsupportedVersion();
                } else {
                    return Result.ofThrowable(-1, ex.getCause());
                }
            } catch (Throwable throwable) {
                logger.error("Error when querying parameter flow rules", throwable);
                return Result.ofFail(-1, throwable.getMessage());
            }
        }
    
        private boolean isNotSupported(Throwable ex) {
            return ex instanceof CommandNotFoundException;
        }
    
        @PostMapping("/rule")
        @AuthAction(AuthService.PrivilegeType.WRITE_RULE)
        public Result<ParamFlowRuleEntity> apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) {
            Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
            if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) {
                return unsupportedVersion();
            }
            entity.setId(null);
            entity.getRule().setResource(entity.getResource().trim());
            Date date = new Date();
            entity.setGmtCreate(date);
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                //publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
                publishRules(entity.getApp());
                return Result.ofSuccess(entity);
            } catch (ExecutionException ex) {
                logger.error("Error when adding new parameter flow rules", ex.getCause());
                if (isNotSupported(ex.getCause())) {
                    return unsupportedVersion();
                } else {
                    return Result.ofThrowable(-1, ex.getCause());
                }
            } catch (Throwable throwable) {
                logger.error("Error when adding new parameter flow rules", throwable);
                return Result.ofFail(-1, throwable.getMessage());
            }
        }
    
        private <R> Result<R> checkEntityInternal(ParamFlowRuleEntity entity) {
            if (entity == null) {
                return Result.ofFail(-1, "bad rule body");
            }
            if (StringUtil.isBlank(entity.getApp())) {
                return Result.ofFail(-1, "app can't be null or empty");
            }
            if (StringUtil.isBlank(entity.getIp())) {
                return Result.ofFail(-1, "ip can't be null or empty");
            }
            if (entity.getPort() == null || entity.getPort() <= 0) {
                return Result.ofFail(-1, "port can't be null");
            }
            if (entity.getRule() == null) {
                return Result.ofFail(-1, "rule can't be null");
            }
            if (StringUtil.isBlank(entity.getResource())) {
                return Result.ofFail(-1, "resource name cannot be null or empty");
            }
            if (entity.getCount() < 0) {
                return Result.ofFail(-1, "count should be valid");
            }
            if (entity.getGrade() != RuleConstant.FLOW_GRADE_QPS) {
                return Result.ofFail(-1, "Unknown mode (blockGrade) for parameter flow control");
            }
            if (entity.getParamIdx() == null || entity.getParamIdx() < 0) {
                return Result.ofFail(-1, "paramIdx should be valid");
            }
            if (entity.getDurationInSec() <= 0) {
                return Result.ofFail(-1, "durationInSec should be valid");
            }
            if (entity.getControlBehavior() < 0) {
                return Result.ofFail(-1, "controlBehavior should be valid");
            }
            return null;
        }
    
        @PutMapping("/rule/{id}")
        @AuthAction(AuthService.PrivilegeType.WRITE_RULE)
        public Result<ParamFlowRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
                                                                  @RequestBody ParamFlowRuleEntity entity) {
            if (id == null || id <= 0) {
                return Result.ofFail(-1, "Invalid id");
            }
            ParamFlowRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofFail(-1, "id " + id + " does not exist");
            }
    
            Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);
            if (checkResult != null) {
                return checkResult;
            }
            if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) {
                return unsupportedVersion();
            }
            entity.setId(id);
            Date date = new Date();
            entity.setGmtCreate(oldEntity.getGmtCreate());
            entity.setGmtModified(date);
            try {
                entity = repository.save(entity);
                publishRules(entity.getApp());
                //publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
                return Result.ofSuccess(entity);
            } catch (ExecutionException ex) {
                logger.error("Error when updating parameter flow rules, id=" + id, ex.getCause());
                if (isNotSupported(ex.getCause())) {
                    return unsupportedVersion();
                } else {
                    return Result.ofThrowable(-1, ex.getCause());
                }
            } catch (Throwable throwable) {
                logger.error("Error when updating parameter flow rules, id=" + id, throwable);
                return Result.ofFail(-1, throwable.getMessage());
            }
        }
    
        @DeleteMapping("/rule/{id}")
        @AuthAction(PrivilegeType.DELETE_RULE)
        public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
            if (id == null) {
                return Result.ofFail(-1, "id cannot be null");
            }
            ParamFlowRuleEntity oldEntity = repository.findById(id);
            if (oldEntity == null) {
                return Result.ofSuccess(null);
            }
    
            try {
                repository.delete(id);
                publishRules(oldEntity.getApp());
                //publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get();
                return Result.ofSuccess(id);
            } catch (ExecutionException ex) {
                logger.error("Error when deleting parameter flow rules", ex.getCause());
                if (isNotSupported(ex.getCause())) {
                    return unsupportedVersion();
                } else {
                    return Result.ofThrowable(-1, ex.getCause());
                }
            } catch (Throwable throwable) {
                logger.error("Error when deleting parameter flow rules", throwable);
                return Result.ofFail(-1, throwable.getMessage());
            }
        }
    
    //    private CompletableFuture publishRules(String app, String ip, Integer port) {
    //        List rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    //        return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
    //    }
    
        private void publishRules(String app) throws Exception {
            List<ParamFlowRuleEntity> rules = repository.findAllByApp(app);
            rulePublisher.publish(app, rules);
        }
    
        private <R> Result<R> unsupportedVersion() {
            return Result.ofFail(4041,
                    "Sentinel client not supported for parameter flow control (unsupported version or dependency absent)");
        }
    
        private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271

    启动

    修改nacos实际配置,找到com.alibaba.csp.sentinel.dashboard.DashboardApplication右键启动即可。

    编译打包

    去到sentinel-dashboard模块根目录执行相关命令打包

    mvn clean package -DskipTests
    
    • 1

    在项目的 target 目录找到sentinel-dashboard.jar ,执行命令即可启动

    java -jar sentinel-dashboard.jar
    
    • 1

    仓库地址

    https://gitee.com/liu1204/Sentinel,1.8.0分支(基于官方v1.8.0修改)

    参考

    Alibaba Sentinel 1.8.1规则持久化-推模式【基于Nacos 1.3.2】_Jax_u90b9的博客-CSDN博客

  • 相关阅读:
    FBX SDK下载安装教程
    【STM32】MDK下的C语言基础
    BERT 快速理解——思路简单描述
    java计算机毕业设计求职招聘网站设计与实现源码+mysql数据库+系统+lw文档+部署
    Python数据挖掘入门进阶与实用案例:自动售货机销售数据分析与应用
    面渣逆袭:微服务三十三问,两万字图文详解!速收藏!
    go拾遗(2)-函数返回数组、多个值、不显示指定返回
    YOLO改进系列之注意力机制(CoTAttention模型介绍)
    【无标题】
    JavaEE:多线程(3):案例代码
  • 原文地址:https://blog.csdn.net/LuoQuHen/article/details/126920572