0


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

文章目录

推送模式

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

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

在这里插入图片描述

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

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

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

在这里插入图片描述

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

配置yml

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

编写处理类

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

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,
                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,
                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,
                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,
                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,
                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下创建配置目录

META-INF/services

,然后添加文件

com.alibaba.csp.sentinel.init.InitFunc

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

it.aq.cheetah.config.FilePersistence

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

演示

编写测试类

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

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

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

在这里插入图片描述

然后去看文件

flow-rule.json

,发现存到了本地文件中

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

在这里插入图片描述

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

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

修改nacos在sentinel中生效

引入依赖

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

<!--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配置文件中只需要写一些基本的配置就可以了。

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

在nacos中配置sentinel信息

spring:cloud:sentinel:transport:# 跟控制台交流的端口,随意指定一个未使用的端口即可port:9998# 指定控制台服务的地址dashboard: localhost:8080# sentinel用nacos作为数据源的配置datasource:#流控管理(这个名称可以自定义)flow-control:# 告诉sentinel用nacos作为数据源nacos:# 配置中心里执行文件的 dataIddataId: shop-product-flow.json  
            # 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。
publicenumRuleType{/**
     * flow.
     */FLOW("flow",FlowRule.class),/**
     * degrade.
     */DEGRADE("degrade",DegradeRule.class),/**
     * param flow.
     */PARAM_FLOW("param-flow",ParamFlowRule.class),/**
     * system.
     */SYSTEM("system",SystemRule.class),/**
     * authority.
     */AUTHORITY("authority",AuthorityRule.class),/**
     * gateway flow.
     */GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),/**
     * api.
     */GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
shop-product-flow.json

文件中配置【流控规则】

[{"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 中配置的文件直接在

sentinel dashboard

中生效,但是我们在

sentinel dashboard

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

修改sentinel在nacos中生效

Sentinel 控制台提供

DynamicRulePublisher

DynamicRuleProvider

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

下载源码

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

下载dashboard的代码源码。

在这里插入图片描述

解压之后打开

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的信息以及转换器类。

更改代码

application.properties 

中增加 nacos 的配置

# nacos 配置
nacos.serverAddr=localhost:8848
nacos.username=nacos
nacos.password=nacos
NacosConfig

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

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

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

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

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

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

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

@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中

@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);
        rules = repository.saveAll(rules);returnResult.ofSuccess(rules);}catch(Throwable throwable){
        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);
      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 持久化两种模式”的评论:

还没有评论