0


【Spring Cloud】全面解析服务容错中间件 Sentinel 持久化两种模式

文章目录

推送模式

Sentinel 规则的推送有下面三种模式:
在这里插入图片描述

通过前面的讲解,我们已经知道,可以通过 Dashboard 来为每个 Sentinel 客户端设置各种各样的规则,这种属于原始模式。这种模式存在一个问题,就是这些规则默认是存放在内存中的,极不稳定,所以需要将其持久化。

在这里插入图片描述

为了达到持久化的目标,我们需要进行改造,改造的方案有两种:本地文件持久化(拉模式)、配置中心持久化(推模式)

本地文件持久化(拉模式)

拉模式又被称为 pull 模式,它的数据源(如本地文件、RDBMS等)一般是可写入的。本地文件数据源会定时轮询文件的变更,读取规则。这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。以本地文件数据源为例,推送过程如下图所示:

在这里插入图片描述

首先 Sentinel 控制台通过API将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。使用 pull模式的数据源时一般不需要对Sentinel控制台进行改造。这种实现方法好处是简单,坏处是无法保证监控数据的一致性。

配置yml

  1. #数据库配置spring:cloud:sentinel:eager:truetransport:port:9998#跟控制台交流的端口,随意指定一个未使用的端口即可dashboard: localhost:8080#指定控制台服务的地址filter:enabled:false

编写处理类

实现 InitFunc 接口,在 init 中处理 DataSource 初始化逻辑,并利用 SPI 机制实现加载。

  1. publicclassFilePersistenceimplementsInitFunc{@Value("${spring.application.name}")privateString applicationName;@Overridepublicvoidinit()throwsException{//创建规则文件String ruleDir =System.getProperty("user.home")+"/sentinel-rules/"+ applicationName;String flowRulePath = ruleDir +"/flow-rule.json";String degradeRulePath = ruleDir +"/degrade-rule.json";String systemRulePath = ruleDir +"/system-rule.json";String authorityRulePath = ruleDir +"/authority-rule.json";String paramFlowRulePath = ruleDir +"/param-flow-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);this.createFileIfNotExits(paramFlowRulePath);//流控规则//创建流控规则的可读数据源ReadableDataSource<String,List<FlowRule>> flowRuleRDS =newFileRefreshableDataSource<>(flowRulePath,
  2. source ->JSON.parseObject(source,newTypeReference<List<FlowRule>>(){}));//将可读数据源注册至 FlowRuleManager,这样当规则文件发生变化时,就会更新规则到内存FlowRuleManager.register2Property(flowRuleRDS.getProperty());WritableDataSource<List<FlowRule>> flowRuleWDS =newFileWritableDataSource<>(flowRulePath,this::encodeJson);//将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.//这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);//降级规则ReadableDataSource<String,List<DegradeRule>> degradeRuleRDS =newFileRefreshableDataSource<>(degradeRulePath,
  3. source ->JSON.parseObject(source,newTypeReference<List<DegradeRule>>(){}));DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());WritableDataSource<List<DegradeRule>> degradeRuleWDS =newFileWritableDataSource<>(degradeRulePath,this::encodeJson);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);//系统规则ReadableDataSource<String,List<SystemRule>> systemRuleRDS=newFileRefreshableDataSource<>(systemRulePath,
  4. source ->JSON.parseObject(source,newTypeReference<List<SystemRule>>(){}));SystemRuleManager.register2Property(systemRuleRDS.getProperty());WritableDataSource<List<SystemRule>> systemRuleWDS =newFileWritableDataSource<>(systemRulePath,this::encodeJson);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);//授权规则ReadableDataSource<String,List<AuthorityRule>> authorityRuleRDS =newFileRefreshableDataSource<>(authorityRulePath,
  5. source->JSON.parseObject(source,newTypeReference<List<AuthorityRule>>(){}));AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());WritableDataSource<List<AuthorityRule>> authorityRuleWDS =newFileWritableDataSource<>(authorityRulePath,this::encodeJson);WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);//热点参数规则ReadableDataSource<String,List<ParamFlowRule>> paramFlowRuleRDS =newFileRefreshableDataSource<>(paramFlowRulePath,
  6. source->JSON.parseObject(source,newTypeReference<List<ParamFlowRule>>(){}));ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS =newFileWritableDataSource<>(paramFlowRulePath,this::encodeJson);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);}}
  • FileRefreshableDataSource:每次更新规则时自动读取持久化文件更新到map缓存。
  • FileWritableDataSource:写数据源,将 sentinel 控制台发送过来的规则信息写到持久化文件中。在客户端的socket接收到规则信息后,更新缓存的时候也会将规则信息写入文件中持久化。

添加配置

在resources下创建配置目录

  1. META-INF/services

,然后添加文件

  1. com.alibaba.csp.sentinel.init.InitFunc

,在文件中添加配置类的全路径

  1. it.aq.cheetah.config.FilePersistence

这样当在 Dashboard 中修改了配置后,Dashboard 会调用客户端的接口修改客户端内存中的值,同时将配置写入文件中,这样操作的话规则是实时生效的,如果是直接修改文件中的内容,这样需要等定时任务3秒后执行才能读到最新的规则。接下来我们演示下:

演示

编写测试类

  1. @RestController@RequestMapping("/product2")@Slf4jpublicclassProductController2{@RequestMapping("/test")@SentinelResource(value ="test")publicStringtest(){return"product2";}}

启动项目,发现在目录下生成了空的规则文件

在这里插入图片描述
在页面上增加流控规则

在这里插入图片描述

然后去看文件

  1. flow-rule.json

,发现存到了本地文件中

在这里插入图片描述
接着我们仿照该规则仿写一个熔断规则,然后查看网页数据确实生效了

在这里插入图片描述

配置中心持久化(推模式)

推模式又叫 Push 模式,它是通过注册中心实现的,Sentinel控制台——>配置中心——>Sentinel数据源——>Sentinel
在这里插入图片描述
用户不仅可以通过sentinel控制台进行更新,也可以通过nacos配置中心进行更新,所以在sentinel控制台或nacos中修改规则后,都需要通知对方刷新最新的配置。

修改nacos在sentinel中生效

引入依赖

我们在之前项目的基础上引入新的依赖

  1. <!--nacos配置中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--以nacos作为sentinel数据源的依赖--><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>

配置文件

nacos 配置:因为我们用nacos作为了配置中心,我们可以将sentinel的基本配置放入到nacos中就可以了,所以当前服务的yml配置文件中只需要写一些基本的配置就可以了。

  1. spring:cloud:nacos:discovery:server-addr: localhost:8848config:server-addr: localhost:8848file-extension: yml

在nacos中配置sentinel信息

  1. spring:cloud:sentinel:transport:# 跟控制台交流的端口,随意指定一个未使用的端口即可port:9998# 指定控制台服务的地址dashboard: localhost:8080# sentinel用nacos作为数据源的配置datasource:#流控管理(这个名称可以自定义)flow-control:# 告诉sentinel用nacos作为数据源nacos:# 配置中心里执行文件的 dataIddataId: shop-product-flow.json
  2. # nacos的地址serverAddr: 127.0.0.1:8848# 指定文件配置的是哪种规则rule-type: flow

注意:如果使用的 namespace 不是默认的,记得配置 namespace 参数。

  • dataId:需要告诉 sentinel 读取配置中心中的哪个配置文件;
  • rule-type:告诉 sentinel 配置文件配置的控制规则,flow:流控、degrade:熔断、param-flow 热点参数,想看有哪些规则参数可以查看com.alibaba.cloud.sentinel.datasource包下的枚举类:RuleType。
  1. publicenumRuleType{/**
  2. * flow.
  3. */FLOW("flow",FlowRule.class),/**
  4. * degrade.
  5. */DEGRADE("degrade",DegradeRule.class),/**
  6. * param flow.
  7. */PARAM_FLOW("param-flow",ParamFlowRule.class),/**
  8. * system.
  9. */SYSTEM("system",SystemRule.class),/**
  10. * authority.
  11. */AUTHORITY("authority",AuthorityRule.class),/**
  12. * gateway flow.
  13. */GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),/**
  14. * api.
  15. */GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
  1. shop-product-flow.json

文件中配置【流控规则】

  1. [{"clusterConfig":{"acquireRefuseStrategy":0,"clientOfflineTime":2000,"fallbackToLocalWhenFail":true,"resourceTimeout":2000,"resourceTimeoutStrategy":0,"sampleCount":10,"strategy":0,"thresholdType":0,"windowIntervalMs":1000},"clusterMode":false,"controlBehavior":0,"count":10.0,"grade":1,"limitApp":"default","maxQueueingTimeMs":500,"resource":"/product2/test","strategy":0,"warmUpPeriodSec":10}]

在这里插入图片描述

然后去 dashboard 中查看,发现流控规则已经在控制中显示了

在这里插入图片描述
目前我们已经实现了在 nacos 中配置的文件直接在

  1. sentinel dashboard

中生效,但是我们在

  1. sentinel dashboard

中修改了配置,nacos 是不会监听到并进行修改的。接下来我们实现一下通过 sentinel 控制台设置的规则直接持久化到 nacos配置中心。

修改sentinel在nacos中生效

Sentinel 控制台提供

  1. DynamicRulePublisher

  1. DynamicRuleProvider

接口用于实现应用维度的规则推送和拉取。

下载源码

  1. https://github.com/alibaba/Sentinel/releases

下载dashboard的代码源码。

在这里插入图片描述

解压之后打开

  1. sentinel-dashboard

项目,将 pom.xml 文件中作用域为 test 的注释掉,注释掉后默认的作用域为 compile。

  • test:作用域表示该依赖项只在测试时有用,在编译和运行时不会被用到。
  • compile:作用域范围的依赖项在所有情况下都是有效的,包括编译、运行和测试。

把 test 包下的两个类复制过来

在这里插入图片描述

  • NacosConfigUtil 类主要就是 nacos 配置的规则,比如配置文件的后缀,分组Group_ID等等。因为我用的分组是默认分组,所以改为DEFAULT_GROUP,我之前的规则文件是shop-product-flow.json,所以我把规则文件后缀FLOW_DATA_ID_POSTFIX改为"-flow.json"。
  • NacosConfig类是为了注入nacos的信息以及转换器类。

更改代码

  1. application.properties

中增加 nacos 的配置

  1. # nacos 配置
  2. nacos.serverAddr=localhost:8848
  3. nacos.username=nacos
  4. nacos.password=nacos
  1. NacosConfig

修改为从配置文件中获取nacos配置

  1. @BeanpublicConfigServicenacosConfigService()throwsException{Properties properties =newProperties();//Nacos地址
  2. properties.put("serverAddr", serverAddr);//Nacos用户名
  3. properties.put("username", username);//Nacos密码
  4. properties.put("password", password);returnConfigFactory.createConfigService(properties);}

  1. com.alibaba.csp.sentinel.dashboard.rule.FlowRuleApiPublisher#publish

方法中增加推送到nacos的逻辑代码

  1. //将规则推送到nacos
  2. configService.publishConfig(app +NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules));

  1. com.alibaba.csp.sentinel.dashboard.rule.FlowRuleApiProvider#getRules

方法中修改为从nacos中读取配置的逻辑

  1. @OverridepublicList<FlowRuleEntity>getRules(String appName)throwsException{String rules = configService.getConfig(appName +NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID,3000);if(StringUtil.isEmpty(rules)){returnnewArrayList<>();}return converter.convert(rules);}

改造流控的controller类FlowControllerV1,将配置保存到内存中的逻辑改为保存到nacos中

  1. @Autowired@Qualifier("flowRuleDefaultProvider")privateDynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("flowRuleDefaultPublisher")privateDynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;@GetMapping("/rules")@AuthAction(PrivilegeType.READ_RULE)publicResult<List<FlowRuleEntity>>apiQueryMachineRules(@RequestParamString app,@RequestParamString ip,@RequestParamInteger port){......try{// List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);//从nacos中读取规则List<FlowRuleEntity> rules = ruleProvider.getRules(app);
  2. rules = repository.saveAll(rules);returnResult.ofSuccess(rules);}catch(Throwable throwable){
  3. logger.error("Error when querying flow rules", throwable);returnResult.ofThrowable(-1, throwable);}}privatevoidpublishRules(String app,String ip,Integer port)throwsException{//将规则推送到nacosList<FlowRuleEntity> rules = repository.findAllByApp(app);
  4. rulePublisher.publish(app, rules);// List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));// return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);}//其余调用publishRules方法的地方做下简单调整

演示

启动当前项目,流控规则中存在我们之前在nacos中创建的文件,我们将原来的单机阈值从10改为12,然后保存。查看nacos中配置文件的数据,发现已经生效了。

在这里插入图片描述
至于其他规则,大家可以自行实现,此处就不一一实现了

在这里插入图片描述

总结

到这儿,服务容错中间件Sentinel的两种持久化模式就已经介绍完了。下一篇将为大家带来Feign整合容错组件 Sentinel 的文章,敬请期待吧!

后续的文章,我们将继续完善我们的微服务系统,集成更多的Alibaba组件。想要了解更多JAVA后端知识,请点击文末名片与我交流吧。留下您的一键三连,让我们在这个寒冷的东西互相温暖吧!

参考链接:


本文转载自: https://blog.csdn.net/Qingai521/article/details/138967458
版权归原作者 阿Q说代码 所有, 如有侵权,请联系我们删除。

“【Spring Cloud】全面解析服务容错中间件 Sentinel 持久化两种模式”的评论:

还没有评论