springcloudalibaba配置sentinel持久化数据到nacos实战详细说明

前言

由于项目中使用了springcloudalibaba这套框架,使用sentinel做熔断降级功能,在Sentinel-Dashboard中配置规则是存储在内存之中,重启应用就会丢失,所以实际生产环境中需要配置规则的持久化实现。
搜了一下网上介绍规则持久化的文章,发现介绍的不是很全面,因此,在这里,我把我的时间经验分享出来。

Sentinel持久化介绍

在这里插入图片描述
存在三种持久化模式,生产环境一般使用push模式,该模式的工作原理如下图:

Sentinel-Dashboard统一管理配置,然后将规则统一推送到Nacos并持久化(生成配置文件),最后客户端监听Nacos,获取配置的Rule。

换句话说就是实现Sentinel Dashboard与Nacos之间的相互通信:
Sentinel-Dashboard界面配置流控规则—发布/推送—>Nacos生成配置文件并持久化;
通过Nacos配置文件修改流控规则—拉取—>Sentinel-Dashboard界面显示最新的流控规则。

目前官方提供的Sentinel Dashboard是不支持操作nacos的,配置的规则都是存放在内存的,因此,我们需要对Sentinel Dashboard进行改造。

下载Sentinel源代码

可以去github官网下载源码

使用idea打开界面如下:
在这里插入图片描述
我们可以看到Sentinel-Dashboard这个目录,这个就是sentinel的配置源码了

引入依赖

打开Sentinel-Dashboard目录的pom.xml文件,加入以下依赖:

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

修改代码

复制nacos配置文件
把src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos包下的文件复制到src/main/java/com/alibaba/csp/sentinel/dashboard/rule包下
在这个包下只有发布和读取流控的规则,我们要做降级规则持久化,就需要自己建发布和读取降级的规则如下:

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<String, List<DegradeRuleEntity>> converter;

    @Override
    public List<DegradeRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(NacosConfigUtil.DESGRADE_DATA_ID_POSTFIX,
                appName, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}
@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<DegradeRuleEntity>, String> converter;

    @Override
    public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
        configService.publishConfig(NacosConfigUtil.DESGRADE_DATA_ID_POSTFIX,
                app, converter.convert(rules));
    }
}

如下图:
在这里插入图片描述

修改NacosConfig文件

添加降级规则编码和解码方法,自定义产生了ConfigService对象,手动指定nacos的地址和指定的namespace

@Configuration
public class NacosConfig {

    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }
    @Bean
    public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
        return s -> JSON.parseArray(s, FlowRuleEntity.class);
    }

    @Bean
    public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
        return s -> JSON.parseArray(s, DegradeRuleEntity.class);
    }

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        Properties properties = new Properties();
        properties.put("serverAddr", "172.16.88.8:8848");
        properties.put("namespace", "sentinel");
        return ConfigFactory.createConfigService(properties);
    }
}

修改工具类NacosConfigUtil

增加如下配置:

    public static final String GROUP_ID = "SENTINEL_GROUP";
    public static final String FLOW_DATA_ID_POSTFIX = "flow-rules";
    public static final String DESGRADE_DATA_ID_POSTFIX = "degrade-rules";

修改降级接口DegradeController

依赖注入

@Autowired
+    private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
+
+    @Autowired
+    private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;

修改apiQueryMachineRules方法为,通过nacos查询规则:

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 = ruleProvider.getRules(app);

            logger.info("app = {},读取降级规则完成", app);
            if (rules != null && !rules.isEmpty()) {
                for (DegradeRuleEntity entity : rules) {
                    entity.setApp(app);
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("queryApps error:", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }

修改publishRules方法改为如下,将修改的规则发布到nacos

 private boolean publishRules(String app, String ip, Integer port) {
        List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        try {
            logger.info("app = {},推送降级规则完成,rules = {}", app, JSONObject.toJSONString(rules));
            rulePublisher.publish(app, rules);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
    }

修改流控接口FlowControllerV1

依赖注入

    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;

    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

修改apiQueryMachineRules方法,将从内存查询规则改为从nacos查询

@GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,
                                                             @RequestParam String ip,
                                                             @RequestParam 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<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);
            //rules = repository.saveAll(rules);
            List<FlowRuleEntity> rules = ruleProvider.getRules(app);

            logger.info("app = {},读取规则完成", app);
            if (rules != null && !rules.isEmpty()) {
                for (FlowRuleEntity entity : rules) {
                    entity.setApp(app);
                    if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
                        entity.setId(entity.getClusterConfig().getFlowId());
                    }
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);

        } catch (Throwable throwable) {
            logger.error("Error when querying flow rules", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }

修改publishRules方法,将规则发布到内存改为发布到nacos

private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
        List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        try {
            logger.info("app={},推送规则完成", app);
            rulePublisher.publish(app, rules);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
    }

到这里我们就对控制台改造好了。

改造应用程序通过nacos获取规则

这里的应用程序使用的是springcloudalibaba框架,引入sentinel的其他依赖部分已省略

引入依赖

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

添加配置

feign.sentinel.enabled=true
spring.cloud.sentinel.transport.port=18087
spring.cloud.sentinel.transport.dashboard=http://192.168.88.124:8888
spring.cloud.sentinel.datasource.degrade.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.degrade.nacos.dataId=degrade-rules
spring.cloud.sentinel.datasource.degrade.nacos.groupId=${spring.application.name}
spring.cloud.sentinel.datasource.degrade.nacos.namespace=sentinel
spring.cloud.sentinel.datasource.degrade.nacos.data-type=json
spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade

到这里我们的程序就可以订阅nacos的熔断降级和限流的规则变化了。

效果图

添加降级规则
在这里插入图片描述
nacos查询降级规则
在这里插入图片描述
在这里插入图片描述

改造后代码下载

可以在https://download.csdn.net/download/weixin_45973130/59129508下载sentinelg-dashboard改造后的源码。


版权声明:本文为weixin_45973130原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。