天天看点

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

前面两篇讲了不用springcloud做粘合,直接springboot+dubbo+nacos+sentinel的搭建

这篇讲用springcloud做粘合是怎么搞的

一、springcloud+sentinel

在前面的项目的基础上加入

<!--sentinel 核心环境 依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
           

application.yml加入配置

sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
           
springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

代码中用@SentinelResource标记要限流的资源

@RestController
public class AccountController {

    @Autowired
    AccountService accountService;

    @SentinelResource(value = "accountController-get")
    @RequestMapping(value = "account/get", method = RequestMethod.GET)
    public String get(String userId) throws InterruptedException {
        Thread.sleep(1000);
        return "done";
    }

}
           

启动后调用一下这个controller这样才能在sentinel界面看到

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

添加一个流控规则试一下

频繁多点几次就会出现限流

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

二、springcloud+dubbo+sentinel

前面讲的相当于是直接用springcloud+sentinel,在http接口的地方用@SentinelResource标记资源。

下面讲在dubbo的RPC调用的时候怎么结合springcloud+sentinel用

引入依赖

<!--sentinel 核心环境 依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
      
        <!-- sentinel与dubbo适配需要的适配   对于 Apache Dubbo 2.7.x 及以上版本-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-apache-dubbo-adapter</artifactId>
            <version>1.7.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.7.2</version>
        </dependency>
           

注意要加入sentinel-transport-simlpe-http,不然启动要报错

Exception in thread "Thread-16" java.lang.NoClassDefFoundError: com/alibaba/csp/sentinel/log/CommandCenterLog

启动起来,然后出发一下dubbo的RPC调用。就能在sentinel的控制界面的簇点链路中看到了

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

三、sentinel配置的规则做持久化

目前这样,sentinel上面配置的流控规则这些,一旦把sentinel重启就会消失。

一般来说,规则的推送有下面三种模式

推送模式 说明 优点 缺点
原始模式 API 将规则推送至客户端并直接更新到内存中,扩展写数据源(

WritableDataSource

简单,无任何依赖 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
Pull 模式 扩展写数据源(

WritableDataSource

), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等
简单,无任何依赖;规则持久化 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
Push 模式 扩展读数据源(

ReadableDataSource

),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。
规则持久化;一致性;快速 引入第三方依赖

1.原始模式

如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更新到内存中:

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

这种做法的好处是简单,无依赖;坏处是应用重启规则就会消失,仅用于简单测试,不能用于生产环境。

2.Pull模式

pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。

使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 

WritableDataSourceRegistry

 中。

原理:

本地文件数据源会定时轮询文件的变更,读取规则。

这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。

以本地文件数据源为例,推送过程如下图所示:

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。

使用 pull 模式的数据源时一般不需要对 Sentinel 控制台进行改造。

这种实现方法好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性。

Pull 优缺点

优点

简单,无任何依赖

没有额外依赖

缺点

不保证一致性(规则是使用

FileRefreshableDataSource

定时更新,会有延迟)

实时性不保证(规则是使用

FileRefreshableDataSource

定时更新)

拉取过于频繁也可能会有性能问题

由于文件存储于本地,容易丢失

以本地文件数据源为例

在上面已有了的依赖的情况下加入依赖

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>1.7.2</version>
        </dependency>
           

常量类定义规则文件的目录和名字

package com.sid.config;

import java.util.HashMap;
import java.util.Map;

/**
 * 常量类,主要是定义规则文件的目录和名字
 * */
public class PersistenceRuleConstant {
    /**
     * 存储文件路径
     */
    public static final String storePath = System.getProperty("user.home") + "\\sentinel\\rules\\order-app\\";

    /**
     * 各种存储sentinel规则映射map
     */
    public static final Map<String, String> rulesMap = new HashMap<String, String>();

    //流控规则文件
    public static final String FLOW_RULE_PATH = "flowRulePath";

    //降级规则文件
    public static final String DEGRAGE_RULE_PATH = "degradeRulePath";

    //授权规则文件
    public static final String AUTH_RULE_PATH = "authRulePath";

    //系统规则文件
    public static final String SYSTEM_RULE_PATH = "systemRulePath";

    //热点参数文件
    public static final String HOT_PARAM_RULE = "hotParamRulePath";

    static {
        rulesMap.put(FLOW_RULE_PATH, storePath + "flowRule.json");
        rulesMap.put(DEGRAGE_RULE_PATH, storePath + "degradeRule.json");
        rulesMap.put(SYSTEM_RULE_PATH, storePath + "systemRule.json");
        rulesMap.put(AUTH_RULE_PATH, storePath + "authRule.json");
        rulesMap.put(HOT_PARAM_RULE, storePath + "hotParamRule.json");
    }
}
           

文件操作类:如果规则文件不存在就创建对应的目录和对应的规则文件

package com.sid.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 文件操作类,如果规则文件不存在就创建对应的目录和对应的规则文件
 * */
public class RuleFileUtils {
    private static final Logger logger = LoggerFactory.getLogger(RuleFileUtils.class);

    /**
     * 方法实现说明:若路径不存在就创建路径
     *
     * @param filePath:文件存储路径
     */
    public static void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            logger.info("创建Sentinel规则目录:{}", filePath);
            file.mkdirs();
        }
    }


    /**
     * 方法实现说明:若文件不存在就创建路径
     *
     * @param ruleFileMap 规则存储文件
     */
    public static void createFileIfNotExits(Map<String, String> ruleFileMap) throws IOException {

        Set<String> ruleFilePathSet = ruleFileMap.keySet();

        Iterator<String> ruleFilePathIter = ruleFilePathSet.iterator();

        while (ruleFilePathIter.hasNext()) {
            String ruleFilePathKey = ruleFilePathIter.next();
            String ruleFilePath = PersistenceRuleConstant.rulesMap.get(ruleFilePathKey).toString();
            File ruleFile = new File(ruleFilePath);
            if (ruleFile.exists()) {
                logger.info("创建Sentinel 规则文件:{}", ruleFile);
                ruleFile.createNewFile();
            }
        }
    }
}
           

 规则的编码和解码操作类

package com.sid.config;

import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

import java.util.List;

/**
 * 规则的编码和解码操作类
 * */
public class RuleListParserUtils {
    /**
     * 流控列表解析器
     */
    public static final Converter<String, List<FlowRule>> flowRuleListParser = new Converter<String, List<FlowRule>>() {
        @Override
        public List<FlowRule> convert(String source) {
            return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
            });
        }
    };

    /**
     * 流控列表 编码器
     */
    public static final Converter<List<FlowRule>, String> flowRuleEnCoding = new Converter<List<FlowRule>, String>() {
        @Override
        public String convert(List<FlowRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source,
            new TypeReference<List<DegradeRule>>() {
            });

    public static final Converter<List<DegradeRule>, String> degradeRuleEnCoding = new Converter<List<DegradeRule>, String>() {
        @Override
        public String convert(List<DegradeRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source,
            new TypeReference<List<SystemRule>>() {
            });

    public static final Converter<List<SystemRule>, String> systemRuleEnCoding = new Converter<List<SystemRule>, String>() {
        @Override
        public String convert(List<SystemRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON
            .parseObject(source, new TypeReference<List<AuthorityRule>>() {
            });


    public static final Converter<List<AuthorityRule>, String> authorityRuleEnCoding = new Converter<List<AuthorityRule>, String>() {
        @Override
        public String convert(List<AuthorityRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON
            .parseObject(source, new TypeReference<List<ParamFlowRule>>() {
            });


//    public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = new Converter<List<ParamFlowRule>, String>() {
//        @Override
//        public String convert(List<ParamFlowRule> source) {
//            return JSON.toJSONString(source);
//        }
//    };

    public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = source -> encodeJson(source);

    private static <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }


}
           

pull模式操作类

package com.sid.config;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。
 * <p>
 * 使用时需要在客户端注册数据源:
 * 将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中。
 */
public class PullModeLocalFileDataSource implements InitFunc {

    private static final Logger logger = LoggerFactory.getLogger(PullModeLocalFileDataSource.class);

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    @Override
    public void init() throws Exception {
        logger.info("time:{}读取配置", sdf.format(new Date()));
        try {
            // 创建文件存储目录(若路径不存在就创建路径)
            RuleFileUtils.mkdirIfNotExits(PersistenceRuleConstant.storePath);
            // 创建规则文件()
            RuleFileUtils.createFileIfNotExits(PersistenceRuleConstant.rulesMap);
            // 处理流控规则逻辑
            dealFlowRules();
            // 处理降级规则
            dealDegradeRules();
            // 处理系统规则
            dealSystemRules();
            // 热点参数规则
            dealParamFlowRules();
            //  授权规则
            dealAuthRules();
        } catch (Exception e) {
            logger.error("错误原因:{}", e);
        }

    }

    /**
     * 方法实现说明:处理流控规则逻辑
     */
    private void dealFlowRules() throws FileNotFoundException {
        String ruleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.FLOW_RULE_PATH).toString();
        // 创建流控规则的可读数据源
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(ruleFilePath,
                RuleListParserUtils.flowRuleListParser);
        // 将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<List<FlowRule>>(ruleFilePath,
                RuleListParserUtils.flowRuleEnCoding);

        // 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
        //  这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
    }

    // 处理降级规则
    private void dealDegradeRules() throws FileNotFoundException {
        String degradeRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.DEGRAGE_RULE_PATH).toString();
        // 降级规则
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath,
                RuleListParserUtils.degradeRuleListParser);
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath,
                RuleListParserUtils.degradeRuleEnCoding);
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);

    }

    // 处理系统规则
    private void dealSystemRules() throws FileNotFoundException {
        String systemRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.SYSTEM_RULE_PATH).toString();
        // 系统规则
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath,
                RuleListParserUtils.systemRuleListParser);
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath,
                RuleListParserUtils.systemRuleEnCoding);
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
    }

    // 热点参数规则
    private void dealParamFlowRules() throws FileNotFoundException {
        String paramFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.HOT_PARAM_RULE).toString();
        // 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
                paramFlowRulePath, RuleListParserUtils.paramFlowRuleListParser);
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,
                RuleListParserUtils.paramFlowRuleEnCoding);
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }

    private void dealAuthRules() throws FileNotFoundException {
        String authFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.AUTH_RULE_PATH).toString();
//授权规则
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authFlowRulePath,
                RuleListParserUtils.authorityRuleListParser);
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authFlowRulePath,
                RuleListParserUtils.authorityRuleEnCoding);
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
    }

}
           

 通过SPI扩展机制进行扩展,在微服务工程的resources目录下创建META-INF/services目录,并新建文件名为com.alibaba.csp.sentinel.init.InitFunc文件。内容是PullModeLocalFileDataSource类全路径类名

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

验证

在sentinel dashboard(http://localhost:8080/)中给app-order项目添加流控规则

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

app-order检测到流控规则的变化并产生flowRule.json文件 

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化
[{"clusterConfig":{"fallbackToLocalWhenFail":true,"sampleCount":10,"strategy":0,"thresholdType":0,"windowIntervalMs":1000},"clusterMode":false,"controlBehavior":0,"count":1.0,"grade":1,"limitApp":"default","maxQueueingTimeMs":500,"resource":"com.sid.rpc.service.service.OrderServiceApi:create(java.lang.String,java.lang.String,java.lang.Integer)","strategy":0,"warmUpPeriodSec":10}]
           

直接修改这个flowRule.json文件中的内容,也会在 sentinel dashboard(http://localhost:8080/)中看到变化

重启项目或者重启sentinel dashboard,能看到之前配置的流控信息都在

3.Push模式(持久化到nacos)

生产环境下一般更常用的是 push 模式的数据源。

对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

换句话说就是实现Sentinel Dashboard与Nacos之间的相互通信:

1.Sentinel Dashboard界面配置流控规则---sentinel发布/推送--->Nacos生成配置文件并持久化;

2.通过Nacos配置文件修改流控规则---sentinel拉取--->Sentinel Dashboard界面显示最新的流控规则。

需要注意的是:

在Nacos控制台上修改流控制,虽然可以同步到Sentinel Dashboard,但是Nacos此时应该作为一个流控规则的持久化平台,所以正常操作过程应该是开发者在Sentinel Dashboard上修改流控规则后同步到Nacos,遗憾的是目前Sentinel Dashboard不支持该功能。

试想下,如果公司没有统一在Sentinel Dashboard或Nacos中二选一进行配置,而是一会在Sentinel Dashboard配置,一会在Nacos配置。那么就会出现很严重的问题(流控规则达不到预期,配置数据不一致),所以推荐使用Sentinel Dashboard统一界面进行配置管理流控规则

正因为Sentinel Dashboard当前版本(截至目前为止是1.8.1-SNAPSHOT)暂不支持,但是可以通过改造部分源码实现此功能

修改sentinel-dashboard项目源码

先下载sentinel源码:https://github.com/alibaba/Sentinel

切换到自己对应的分支(1.8.1)

控制台改造主要是为规则实现

  • DynamicRuleProvider:从Nacos上读取配置
  • DynamicRulePublisher:将规则推送到Nacos上

pom中

<!-- for Nacos rule publisher sample -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
        <!--注释掉原文件中的scope,让其不仅在test的时候生效-->
        <!--<scope>test</scope>-->
    </dependency>
           

复制sentinel-dashboard项目下test下的nacos包

src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos到 src/main/java/com/alibaba/csp/sentinel/dashboard/rule下
springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

修改controller中的默认provider & publisher

com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2中

@Autowired
    // @Qualifier("flowRuleDefaultProvider")
		@Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
		// @Qualifier("flowRuleDefaultPublisher")
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
           

打开 /Sentinel-1.8.1/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/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>&nbsp;&nbsp;流控规则</a>
          </li>


把V1去掉,就是这个flowV1改成flow
           
springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

复制过来的这几个类要修改,且新增一个NacosPropertiesConfiguration类

package com.alibaba.csp.sentinel.dashboard.rule.nacos;


import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "sentinel.nacos")
public class NacosPropertiesConfiguration{
    private String serverAddr;
    private String dataId;
    private String groupId = "SENTINEL_GROUP"; // 默认分组
    private String namespace;

//省略getter setter
}
           

NacosConfig要修改为

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
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 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;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@EnableConfigurationProperties(NacosPropertiesConfiguration.class)
@Configuration
public class NacosConfig {

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

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

    @Bean
    public ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws Exception {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr());
        properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace());
        return ConfigFactory.createConfigService(properties);
//        return ConfigFactory.createConfigService("localhost");
    }
}
           

修改FlowRuleNacosPublisher

@Service("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

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

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

修改类FlowRuleNacosProvider

@Service("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

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

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
            NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}
           

修改配置文件application.properties在末尾加入

# nacos config server
sentinel.nacos.serverAddr=localhost:8848
sentinel.nacos.namespace=
sentinel.nacos.group-id=SENTINEL_GROUP
           

 重新打包sentinel项目(记得是把整个sentinel项目重新打包,不是只打包dashboard,怕有东西没打进去)

mvn clean package -DskipTests

启动这个打出来的包

业务系统代码修改

引入依赖

<!-- Sentinel支持采用 Nacos 作为规则配置数据源,引入该适配依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>1.7.2</version>
        </dependency>
           

application.yml添加配置

datasource:
        #自定义的数据源名称,可以多个,必须唯一,可以理解为通过该数据源指定
        #读取哪个位置的哪个文件中的数据,此处表示读取 Nacos 配置中心上的
        #名为 cloudalibaba-sentinel-service 类型为 json 文件中的数据
        #前提是指定的 Nacos 配置中心中要有该文件,该文件中保存的是,Sentinel
        #对当前服务或服务中的接口设置的流控,熔断降级等相关的数据
        ds1:
          nacos:
            server-addr: localhost:8848 #存放数据的数据源地址,通过 Nacos 保存相关数据
            dataId: app-account-flow-rules #读取 Ncaos 配置中心上文件的名称
            groupId: SENTINEL_GROUP #读取 Nacos 配置中心哪个分组id
            data-type: json #读取 Nacos 配置中心上的什么类型的文件
            rule-type: flow #读取的规则类型
           
springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

在nacos中创建sentinel的规则配置文件

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化
[
    {
        "resource": "account-debit",//对应 Sentinel 中的资源名称(接口请求路径,或指定的资源名称)
        "limitApp": "default",//对应 Sentinel 中的来源应用(在Stinel中一般使用默认的)
        "grade": 1, //对应 Sentinel 设置的阈值类型,0 表示线程数,1 表示QPS
        "count": 10,//对应 Sentinel 设置的单机阈值
        "strategy": 0,//对应 Sentinel 设置的流程模式,0直接,1关联,2链路
        "controlBehavior": 0,//对应 Sentinel 流程效果,0快速失败,1WarmUp,2排队等待
        "clusterMode": false //对应 Sentinel 设置的是否集群
    }
]
           
springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

在项目启动后访问该服务中的任意一个接口时,会自动通过配置的 Sentinel 数据源读取 Nacos 上的指定的文件,加载配置内容,获取到针对该服务的流控,熔断,降级等相关数据

(如果启动服务不妨问服务中的任何借口,默认是不会主动去读取数据的,Sentinel 流控页显示为空)

springcloud+dubbo+sentinel+nacos搭建(sentinel规则管理及推送、持久化)一、springcloud+sentinel二、springcloud+dubbo+sentinel三、sentinel配置的规则做持久化

可以尝试在sentinel改变阈值,在nacos中能看到。(失败、好吧,是我理解错了)

在nacos中改变阈值,在sentinel中能看到。(成功)

那在sentinel中改变了阈值,在nacos中看不到,问题出来哪里呢,经过尝试,发现本来我nacos没有用mysql,如果我把我nacos本身的数据存储到mysql中,那sentinel修改后会同步到nacos上

继续阅读