• SpringCloud Alibaba 改造Sentinel Dashboard将熔断规则持久化到Nacos


    Sentinel Dashboard集成Nacos目录:

    SpringCloud Alibaba 改造Sentinel Dashboard将流控规则持久化到Nacos

    SpringCloud Alibaba 改造Sentinel Dashboard将熔断规则持久化到Nacos  本文

    《SpringCloud Alibaba 改造Sentinel Dashboard将流控规则持久化到Nacos》介绍了如何修改Sentinel Dashboard的源代码,使得通过Sentinel Dashboard维护的流控规则自动持久化到Nacos上,应用程序通过订阅Nacos上的配置实现流量控制。

    本文接着介绍如何修改源码实现熔断规则的持久化。

    二. Sentinel Dashboard集成Nacos实现熔断规则持久化

    同前文介绍的集成Nacos实现流控规则持久化类似,为了实现熔断规则持久化,其大致实现步骤仍然是:

    1. 创建新的实现类,实现DynamicRuleProvider接口和DynamicRulePublisher接口。
    2. 修改对应的Controller,注入新的实现类。

    2.1 准备工作

    为了减少代码,更加规范写法,统一流控规则和熔断规则的持久化的写法,首先对之前流控规则的代码予以部分修改,新的包结构如下:

    以下是代码明细:

    NacosConfiguration.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import java.util.Properties;
    
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    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;
    
    /**
     * Nacos配置类
     * @author gang.wang
     * 2021年10月31日
     */
    @EnableConfigurationProperties(NacosPropertiesConfiguration.class)
    @Configuration
    public class NacosConfiguration {
        
        @Bean
        public ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws NacosException {
            Properties properties = new Properties();
            properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr());
            properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace());
            return ConfigFactory.createConfigService(properties);
        }
    }

    NacosConstants.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Bean;
    
    import com.alibaba.csp.sentinel.util.StringUtil;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.nacos.api.config.ConfigService;
    import com.alibaba.nacos.api.exception.NacosException;
    
    /**
     * Nacos常量类
     * @author gang.wang
     * 2021年11月8日
     */
    public class NacosConstants {
        
        private static Logger logger = LoggerFactory.getLogger(NacosConstants.class);
        
        public static final String GROUP_ID = "DEFAULT_GROUP";
        
        /**
         * 流控规则后缀
         */
        public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow";
        
        /**
         * 熔断规则后缀
         */
        public static final String DEGRADE_DATA_ID_POSTFIX = "-sentinel-degrade";
        
        /**
         * 从Nacos server中查询响应规则,并将其反序列化成对应Rule实体
         *
         * @param configService nacos config service
         * @param groupId       组ID
         * @param dataId        Nacos DataId
         * @param clazz         类
         * @param <T>           泛型
         * @return 规则对象列表
         * @throws NacosException 异常
         */
        public static <T> List<T> getRuleEntitiesFromNacos(ConfigService configService, 
                String groupId, String dataId, Class<T> clazz) throws NacosException {
            String rules = configService.getConfig(dataId, groupId, 3000);
            
            logger.info("Pull Rule from Nacos Config : {}", rules);
            
            if (StringUtil.isEmpty(rules)) {
                return new ArrayList<>();
            }
            return JSON.parseArray(rules, clazz);
        }
        
        /**
         * 将规则序列化成为JSON信息,并发布到Nacos上
         * @param <T>
         * @param configService
         * @param groupId
         * @param dataId
         * @param ruleEntities
         * @return
         * @throws NacosException
         */
        @Bean
        public static <T> Boolean setRuleEntitiesFromNacos(ConfigService configService, 
                String groupId, String dataId, List<T> ruleEntities) throws NacosException {
            String ruleEntitiesStr = JSON.toJSONString(ruleEntities);
            logger.info("Push Rule to Nacos Config : {}", ruleEntitiesStr);
            
            return configService.publishConfig(dataId, groupId, ruleEntitiesStr);
        }
        
    }

    NacosPropertiesConfiguration.java的内容依然保持不变:

    package com.alibaba.csp.sentinel.dashboard.rule.nacos;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * 加载Nacos配置
     * @author gang.wang
     * 2021年10月31日
     */
    @ConfigurationProperties(prefix="sentinel.nacos")
    public class NacosPropertiesConfiguration {
        
        /**
         * Nacos服务地址
         */
        private String serverAddr;
        
        private String dataId;
        
        private String groupId = "DEFAULT_GROUP";
        
        private String namespace;
    
        public String getServerAddr() {
            return serverAddr;
        }
    
        public void setServerAddr(String serverAddr) {
            this.serverAddr = serverAddr;
        }
    
        public String getDataId() {
            return dataId;
        }
    
        public void setDataId(String dataId) {
            this.dataId = dataId;
        }
    
        public String getGroupId() {
            return groupId;
        }
    
        public void setGroupId(String groupId) {
            this.groupId = groupId;
        }
    
        public String getNamespace() {
            return namespace;
        }
    
        public void setNamespace(String namespace) {
            this.namespace = namespace;
        }
        
    }

    FlowRuleNacosProvider.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    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.NacosConstants;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosPropertiesConfiguration;
    import com.alibaba.nacos.api.config.ConfigService;
    
    /**
     * 实现从Nacos配置中心获取流控规则
     * @author gang.wang
     * 2021年11月8日
     */
    @Service
    public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
        
        @Autowired
        private NacosPropertiesConfiguration nacosConfigProperties;
        
        @Autowired
        private ConfigService configService;
        
        @Override
        public List<FlowRuleEntity> getRules(String appName) throws Exception {
            
            //定义dataId 应用名+固定后缀
            String dataId = new StringBuilder(appName).append(NacosConstants.FLOW_DATA_ID_POSTFIX).toString();
            
            List<FlowRuleEntity> list = NacosConstants.getRuleEntitiesFromNacos(configService, nacosConfigProperties.getGroupId(), dataId, FlowRuleEntity.class);
            
            return list;
        }
    }

    FlowRuleNacosPublisher.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
    
    import java.util.List;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    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.NacosConstants;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosPropertiesConfiguration;
    import com.alibaba.nacos.api.config.ConfigService;
    
    /**
     * 将通过Sentinel Dashboard上维护的流控规则数据持久化到Nacos中
     * @author gang.wang
     * 2021年11月8日
     */
    @Service
    public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
        
        private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosPublisher.class);
        
        @Autowired
        private NacosPropertiesConfiguration nacosConfigProperties;
        
        @Autowired
        private ConfigService configService;
        
        @Override
        public void publish(String appName, List<FlowRuleEntity> rules) throws Exception {
            
            if(StringUtils.isBlank(appName)) {
                logger.error("传入的AppName为Null");
                return ;
            }
            
            if(null == rules) {
                logger.error("传入的流控规则数据为null");
                return ;
            }
            
            String dataId = new StringBuilder(appName).append(NacosConstants.FLOW_DATA_ID_POSTFIX).toString();
            
            NacosConstants.setRuleEntitiesFromNacos(configService, nacosConfigProperties.getGroupId(), dataId, rules);
        }
    }

    2.2 熔断规则持久化部分代码

    2.2.1 分别创建类实现DynamicRuleProvider接口和DynamicRulePublisher接口

    实现熔断规则持久化的代码和之前流控规则的类似,都需要创建两个类分别实现DynamicRuleProvider接口和DynamicRulePublisher接口,只不过接口的泛型不同,熔断规则的为:List<FlowRuleEntity>

    在com.alibaba.csp.sentinel.dashboard.rule.nacos包下创建degrade包。创建类:DegradeRuleNacosProvider.java和DegradeRuleNacosPublisher.java,分别实现<从Nacos拉取规则并展示在Dashboard上>和<将通过Dashboard维护的熔断规则持久化到Nacos上>这两个功能。

    二者代码实现也同流控规则中的代码类似。

    DegradeRuleNacosProvider.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    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.NacosConstants;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosPropertiesConfiguration;
    import com.alibaba.nacos.api.config.ConfigService;
    
    /**
     * 实现从Nacos配置中心获取熔断规则
     * @author gang.wang
     * 2021年11月15日
     */
    @Service
    public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
        
        @Autowired
        private NacosPropertiesConfiguration nacosConfigProperties;
        
        @Autowired
        private ConfigService configService;
        
        @Override
        public List<DegradeRuleEntity> getRules(String appName) throws Exception {
            
            //定义dataId 应用名+固定后缀
            String dataId = new StringBuilder(appName).append(NacosConstants.DEGRADE_DATA_ID_POSTFIX).toString();
            
            List<DegradeRuleEntity> list = NacosConstants.getRuleEntitiesFromNacos(configService, nacosConfigProperties.getGroupId(), dataId, DegradeRuleEntity.class);
            
            return list;
        }
    }

    DegradeRuleNacosPublisher.java

    package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
    
    import java.util.List;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    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.NacosConstants;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosPropertiesConfiguration;
    import com.alibaba.csp.sentinel.dashboard.rule.nacos.flow.FlowRuleNacosPublisher;
    import com.alibaba.nacos.api.config.ConfigService;
    
    /**
     * 实现将熔断规则持久化到Nacos中
     * @author gang.wang
     * 2021年11月15日
     */
    @Service
    public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
    
    private static Logger logger = LoggerFactory.getLogger(FlowRuleNacosPublisher.class);
        
        @Autowired
        private NacosPropertiesConfiguration nacosConfigProperties;
        
        @Autowired
        private ConfigService configService;
        
        @Override
        public void publish(String appName, List<DegradeRuleEntity> rules) throws Exception {
            
            if(StringUtils.isBlank(appName)) {
                logger.error("传入的AppName为Null");
                return ;
            }
            
            if(null == rules) {
                logger.error("传入的熔断规则数据为null");
                return ;
            }
            
            String dataId = new StringBuilder(appName).append(NacosConstants.DEGRADE_DATA_ID_POSTFIX).toString();
            
            NacosConstants.setRuleEntitiesFromNacos(configService, nacosConfigProperties.getGroupId(), dataId, rules);
        }
    
    }

    2.2.2 修改com.alibaba.csp.sentinel.dashboard.controller.DegradeController,注入新的实现类

    此Controller中只需要修改两个方法即可,分别是:

    1. com.alibaba.csp.sentinel.dashboard.controller.DegradeController.apiQueryMachineRules(String, String, Integer)
    2. com.alibaba.csp.sentinel.dashboard.controller.DegradeController.publishRules(String, String, Integer)

    修改后的代码如下:

    /*
     * Copyright 1999-2018 Alibaba Group Holding Ltd.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    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.client.SentinelApiClient;
    import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
    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);
    
        /**
         * 将规则加载到Sentinel Dashboard的内存中
         */
        @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<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
                //修改为从Nacos中加载熔断规则
                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);
            } 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);
            } 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);
            } 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<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
            //注释掉原有代码
            //return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
            try {
                rulePublisher.publish(app, rules);
                return true;
            } catch(Exception ex) {
                logger.error("Publish degrade rules failed", ex);
                return false;
            }
        }
    
        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;
        }
    }

    2.3 测试通过Sentinel Dashboard维护的熔断规则是否可以持久化到Nacos中

    访问Sentinel Dashboard,维护一条熔断规则,示例如下:

    为了后面验证简单,这里我们定义的熔断规则的含义是:此接口在1000ms内当至少有3次访问,并至少有2次异常,则此接口熔断10秒。

    刷新列表可以看到刚刚维护的信息:

     访问Nacos,查看是否正常存储:

     

     由上可见,通过Sentinel Dashboard维护的熔断规则已经正常持久化到Nacos中了。

    2.4 应用程序接入

    应用程序需要订阅Nacos上的对应DataId,当熔断规则有变化时,Nacos会自动推送到已经接入的应用程序上。其具体接入的方式同之前介绍的流控规则类似。

    首先在application.yml中添加对应的配置。application.yml中与Sentinel相关的配置如下:

    spring:
        sentinel:
          transport: 
            dashboard: 127.0.0.1:8080
          datasource: 
            flow: 
              nacos: 
                server-addr: 127.0.0.1:8848
                namespace: 37c7c263-bdf1-41db-9f34-bf10948be752
                data-id: ${spring.application.name}-sentinel-flow
                group-id: DEFAULT_GROUP
                data-type: json
                rule-type: flow
            degrade: 
              nacos: 
                server-addr: 127.0.0.1:8848
                namespace: 37c7c263-bdf1-41db-9f34-bf10948be752
                data-id: ${spring.application.name}-sentinel-degrade
                group-id: DEFAULT_GROUP
                data-type: json
                rule-type: degrade

    为了配合上面定义的基于异常数的熔断规则,我们修改之前定义的接口,抛出任意异常即可。

    @SentinelResource(value = "hello", blockHandler = "blockHandlerHello")
    @GetMapping("/say")
    public String hello() {
        int a = 10;
        int b = 0;
        int c = a / b;
        return "hello, Gary!";
    }

    启动应用程序,并利用Postman并发访问刚刚我们定义了熔断规则的接口。

     

    可以看到前两次接口访问报500错误,从第三次开始http code就开始等于200,responseBody的值为当前请求已被限流。所以可见我们定义的熔断规则生效了。

    至此熔断规则持久化到Nacos的功能就已完成了!

  • 相关阅读:
    设计模式-装饰器模式
    自定义 RestTemplate 异常处理 (转)
    Jackson 高级应用
    Jackson 的 基本用法
    Jackson转换为Collection、Array
    Jackson中处理map中的null key 或者null value 及实体字段中的null value
    sed
    MySQL server has gone away 异常
    nl命令
    线程池
  • 原文地址:https://www.cnblogs.com/wanggangblog/p/15559449.html
Copyright © 2020-2023  润新知