栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Sentinel同步流控规则到Nacos(Apollo、zookeeper同理)

Sentinel同步流控规则到Nacos(Apollo、zookeeper同理)

1.必看!!!(右边有目录导航)

已集成Nacos、Sentinel并且Sentinel dashboard可正常显示Nacos持久化的流控规则
Sentinel下载sentinel源码:https://github.com/alibaba/Sentinel/archive/refs/tags/1.8.3.zipsentinel-dashboard工程添加lombok依赖、修改Nacos scope新建或修改package、class、enum不再赘婿,详见class和enum的package路径!!已确认无误,复制粘贴当伸手党即可。


    com.alibaba.csp
    sentinel-datasource-nacos
    


    org.projectlombok
    lombok
    
    1.18.16

2.项目目录(下述代码全部在sentinel-dashboard工程)

3.修改文件:sidebar.html

文件目录:

替换内容:

    
    

    
  •   服务流控规则
  • 修改identity.js为(目的:簇点链路添加流控规则调用API改为V2)

    产生影响:

    将流控规则时保存调用的API由V1改为V2(/v2/flow/rules)

    4. 新增配置

    #在resources/application.properties中添加Sentinel -> Nacos的连接信息
    #Nacos -> Sentinel:Nacos -> 服务 -> Sentinel dashboard
    sentinel.nacos.serverAddr=192.168.1.135:8847
    sentinel.nacos.groupId=SENTINEL_GROUP
    sentinel.nacos.namespace=95c0ce18-50e0-4e1b-917e-6429d0c54c5e
    #dataId未使用
    sentinel.nacos.dataId= 
    
    5. 添加/修改同步代码(有问题看标题1)

    添加完后目录:

    实现思路借鉴test/com.alibaba.csp.sentinel.dashboard.rule.nacos

    5.2 NacosPropertiesConfiguration
    package com.alibaba.csp.sentinel.dashboard.config;
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    @Data
    @ConfigurationProperties(prefix="sentinel.nacos")
    public class NacosPropertiesConfiguration{
        private String serverAddr;
        private String groupId = "DEFAULT_GROUP";
        private String namespace;
        private String dataId;
    }
    
    5.3 NacosPropertiesConfiguration
    package com.alibaba.csp.sentinel.dashboard.config;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    
    @Getter
    @AllArgsConstructor
    public enum RuleTypeEnum {
        FLOW("-flow-rules"),
        DEGRADE("-degrade-rules"),
        SYSTEM("-system-rules"),
        AUTHORITY("-authority-rules"),
        PARAM_FLOW("-param-flow-rules");
    
        private String ruleTypePostfix;
    }
    
    5.1 nacos包

    flow/degrade,system/authority/param-flow参考degrade实现NacosConfig

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import com.alibaba.csp.sentinel.dashboard.config.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.nacos.api.PropertyKeyConst;
    import com.alibaba.nacos.api.config.ConfigFactory;
    import com.alibaba.nacos.api.config.ConfigService;
    import com.alibaba.nacos.api.exception.NacosException;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.List;
    import java.util.Properties;
    
    
    @EnableConfigurationProperties(NacosPropertiesConfiguration.class)
    @Configuration
    public class NacosConfig {
    
        @Bean
        public Converter,String> flowRuleEntityEncoder(){
            return JSON::toJSONString;
        }
    
        @Bean
        public Converter> flowRuleDecoder(){
            return s->JSON.parseArray(s,FlowRuleEntity.class);
        }
        @Bean
        public Converter> degradeRuleDecoder(){
            return s->JSON.parseArray(s,DegradeRuleEntity.class);
        }
        @Bean
        public Converter> systemRuleDecoder(){
            return s->JSON.parseArray(s,SystemRuleEntity.class);
        }
        @Bean
        public Converter> authorityRuleDecoder(){
            return s->JSON.parseArray(s,AuthorityRuleEntity.class);
        }
        @Bean
        public Converter> paramFlowRuleDecoder(){
            return s->JSON.parseArray(s,ParamFlowRuleEntity.class);
        }
        @Bean
        public ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws NacosException {
            Properties properties = new Properties();
            properties.put(PropertyKeyConst.NAMESPACE,nacosPropertiesConfiguration.getNamespace());
            properties.put(PropertyKeyConst.SERVER_ADDR,nacosPropertiesConfiguration.getServerAddr());
            return ConfigFactory.createConfigService(properties);
        }
    }
    

    NacosRuleApiProvider

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    public interface NacosRuleApiProvider  {
        T getRules(String app) throws Exception;
    }
    
    

    NacosRuleApiPublisher

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    public interface NacosRuleApiPublisher  {
        void publish(String app, T rules) throws Exception;
    }
    
    

    DegradeRuleNacosApiProvider

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import com.alibaba.csp.sentinel.dashboard.config.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.config.RuleTypeEnum;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosRuleApiProvider;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.nacos.api.config.ConfigService;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Slf4j
    @Component("degradeProvider")
    public class DegradeRuleNacosApiProvider implements NacosRuleApiProvider> {
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter> converter;
        @Autowired
        private NacosPropertiesConfiguration nacosPropertiesConfiguration;
    
        @Override
        public List getRules(String app) throws Exception {
            String dataId = new StringBuilder(app).append(RuleTypeEnum.DEGRADE.getRuleTypePostfix()).toString();
            String rules = configService.getConfig(dataId, nacosPropertiesConfiguration.getGroupId(), 3000);
            log.info("从Nacos配置中心获取{}规则:{}", RuleTypeEnum.DEGRADE.name(), rules);
            if (StringUtils.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return converter.convert(rules);
        }
    
    
    }
    
    

    DegradeRuleNacosPublisher

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import com.alibaba.csp.sentinel.dashboard.config.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.config.RuleTypeEnum;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosRuleApiPublisher;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.csp.sentinel.util.AssertUtil;
    import com.alibaba.nacos.api.config.ConfigService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    
    @Slf4j
    @Component("degradePublisher")
    public class DegradeRuleNacosPublisher implements NacosRuleApiPublisher> {
    
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter, String> converter;
        @Autowired
        private NacosPropertiesConfiguration nacosPropertiesConfiguration;
    
        @Override
        public void publish(String app, List rules) throws Exception {
            AssertUtil.notEmpty(app, "appName 不能为空");
            if (rules == null) {
                return;
            }
            String dataId = new StringBuilder(app).append(RuleTypeEnum.DEGRADE.getRuleTypePostfix()).toString();
            configService.publishConfig(dataId, nacosPropertiesConfiguration.getGroupId(), converter.convert(rules));
            log.info("推送{}到Nacos配置中心,DataId:{},规则:{}", RuleTypeEnum.DEGRADE.name(), dataId, rules);
        }
    }
    

    FlowRuleNacosApiProvider

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.config.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.config.RuleTypeEnum;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosRuleApiProvider;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.nacos.api.config.ConfigService;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Slf4j
    @Component("flowProvider")
    public class FlowRuleNacosApiProvider implements NacosRuleApiProvider> {
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter> converter;
        @Autowired
        private NacosPropertiesConfiguration nacosPropertiesConfiguration;
    
        @Override
        public List getRules(String app) throws Exception {
            String dataId = new StringBuilder(app).append(RuleTypeEnum.FLOW.getRuleTypePostfix()).toString();
            String rules = configService.getConfig(dataId, nacosPropertiesConfiguration.getGroupId(), 3000);
            log.info("从Nacos配置中心获取{}规则:{}", RuleTypeEnum.FLOW.name(), rules);
            if (StringUtils.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return converter.convert(rules);
        }
    
    
    }
    
    

    FlowRuleNacosPublisher

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import com.alibaba.csp.sentinel.dashboard.config.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.config.RuleTypeEnum;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosRuleApiPublisher;
    import com.alibaba.csp.sentinel.datasource.Converter;
    import com.alibaba.csp.sentinel.util.AssertUtil;
    import com.alibaba.nacos.api.config.ConfigService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    
    @Slf4j
    @Component("flowPublisher")
    public class FlowRuleNacosPublisher implements NacosRuleApiPublisher> {
    
        @Autowired
        private ConfigService configService;
        @Autowired
        private Converter, String> converter;
        @Autowired
        private NacosPropertiesConfiguration nacosPropertiesConfiguration;
    
        @Override
        public void publish(String app, List rules) throws Exception {
            AssertUtil.notEmpty(app, "appName 不能为空");
            if (rules == null) {
                return;
            }
            String dataId = new StringBuilder(app).append(RuleTypeEnum.FLOW.getRuleTypePostfix()).toString();
            configService.publishConfig(dataId, nacosPropertiesConfiguration.getGroupId(), converter.convert(rules));
            log.info("推送{}到Nacos配置中心,DataId:{},规则:{}", RuleTypeEnum.FLOW.name(), dataId, rules);
        }
    }
    
    5.4 FlowControllerV2
    //改动:指定依赖注入类型
    @Autowired
    @Qualifier("flowProvider")
    private NacosRuleApiProvider> ruleProvider;
    
    @Autowired
    @Qualifier("flowPublisher")
    private NacosRuleApiPublisher> rulePublisher;
    
    5.5 DegradeController

    package com.alibaba.csp.sentinel.dashboard.controller;
    
    import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
    import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
    import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
    import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
    import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
    import com.alibaba.csp.sentinel.dashboard.domain.Result;
    import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosRuleApiPublisher;
    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 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.*;
    
    import java.util.Date;
    import java.util.List;
    
    
    @RestController
    @RequestMapping("/degrade")
    public class DegradeController {
    
        private final Logger logger = LoggerFactory.getLogger(DegradeController.class);
    
        @Autowired
        private RuleRepository repository;
        @Autowired
        private SentinelApiClient sentinelApiClient;
        @Autowired
        @Qualifier("degradePublisher")
        NacosRuleApiPublisher publisher;
    
        @GetMapping("/rules.json")
        @AuthAction(PrivilegeType.READ_RULE)
        public Result> 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);
                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 apiAddRule(@RequestBody DegradeRuleEntity entity) {
            Result 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 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 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 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  Result 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;
        }
    
        private void publishRules( String app) throws Exception {
            List rules = repository.findAllByApp(app);
            publisher.publish(app, rules);
        }
    }
    

    6. 构建启动DashboardApplication 7.效果展示

    同步前:


    同步后(服务本地配置与控制面板、Nacos配置):

    控制面板
    服务本地Nacos持久化

    转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/741850.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号