一、背景
版本:【Sentinel-1.8.6】
模式:【Push 模式】
参照官网介绍:生产环境下使用Sentinel ,规则管理及推送模式有以下3种模式:
比较之后,目前微服务都使用了各种各样的配置中心,故采用Push 模式来进行持久化,这里也主要介绍集合 Nacos 的持久化。
二、流程结构图
实现思路说明:微服务中增加基于Nacos的写数据源(WritableDataSource),当 Sentinel Dashboard 配置发生变更,则利用 nacos 配置变更通知微服务更新本地缓存。
三、代码整合
1. 在微服务中引入依赖。
com.alibaba.csp sentinel-datasource-nacos
依赖缘由
(ps: 至于为何要引入这个依赖,在此做下展开说明,着急的同学请略过看)
可以看到这个依赖包的源码中只有一个类,那么这个类一定很重要了,看看它具体做了啥:
NacosDataSource 中构造方法如下,里面有个重要的东西: configListener,我们先记住红框框起来的地方。
看看具体的方法 initNacosListener(); 和 loadInitialConfig();
// 初始化 Nacos 监听器 private void initNacosListener() { try { // 根据数据源配置信息初始化Nacos 的配置服务: configService this.configService = NacosFactory.createConfigService(this.properties); // 添加配置监听器. configService.addListener(dataId, groupId, configListener); } catch (Exception e) { RecordLog.warn("[NacosDataSource] Error occurred when initializing Nacos data source", e); e.printStackTrace(); } } // 加载Nacos 已有配置文件 private void loadInitialConfig() { try { T newValue = loadConfig(); if (newValue == null) { RecordLog.warn("[NacosDataSource] WARN: initial config is null, you may have to check your data source"); } getProperty().updateValue(newValue); } catch (Exception ex) { RecordLog.warn("[NacosDataSource] Error when loading initial config", ex); } }
又由于 NacosDataSource 继承自 AbstractDataSource,故此处的 loadConfig() 方法是调用 com.alibaba.csp.sentinel.datasource.AbstractDataSource#loadConfig() :
@Override public T loadConfig() throws Exception { return loadConfig(readSource()); }
查看 readSource() 实现:跳转 NacosDataSource.readSource() 中:
@Override public String readSource() throws Exception { if (configService == null) { throw new IllegalStateException("Nacos config service has not been initialized or error occurred"); } // 原来是获取nacos 中的配置 return configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT); }
综上查看,Nacos 已经实现了读取配置的代码,那么我们只需要实现写入部分以及相关的配置即可。
2. 自己实现 Nacos 写入代码
1.定义 NacosWritableDataSource 类
依据读取部分的代码实现,利用 nacos 的 com.alibaba.nacos.api.config.ConfigService#publishConfig(java.lang.String, java.lang.String, java.lang.String) 方法,既会修改持久化文件,也会同步到对应的微服务。代码如下:
public class NacosWritableDataSourceimplements WritableDataSource { private NacosDataSourceProperties nacosDataSourceProperties; private ConfigService configService; private final Converter configEncoder; private final Lock lock = new ReentrantLock(true); public NacosWritableDataSource(NacosDataSourceProperties nacosDataSourceProperties, Converter configEncoder) { this.nacosDataSourceProperties = nacosDataSourceProperties; this.configEncoder = configEncoder; // 初始化 Nacos configService initConfigService(); } private void initConfigService(){ try { this.configService = NacosFactory.createConfigService(buildProperties(nacosDataSourceProperties)); } catch (NacosException e) { e.printStackTrace(); } } private Properties buildProperties(NacosDataSourceProperties nacosDataSourceProperties) { Properties properties = new Properties(); if (!StringUtils.isEmpty(nacosDataSourceProperties.getServerAddr())) { properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosDataSourceProperties.getServerAddr()); } else { properties.setProperty(PropertyKeyConst.ACCESS_KEY, nacosDataSourceProperties.getAccessKey()); properties.setProperty(PropertyKeyConst.SECRET_KEY, nacosDataSourceProperties.getSecretKey()); properties.setProperty(PropertyKeyConst.ENDPOINT, nacosDataSourceProperties.getEndpoint()); } if (!StringUtils.isEmpty(nacosDataSourceProperties.getNamespace())) { properties.setProperty(PropertyKeyConst.NAMESPACE, nacosDataSourceProperties.getNamespace()); } if (!StringUtils.isEmpty(nacosDataSourceProperties.getUsername())) { properties.setProperty(PropertyKeyConst.USERNAME, nacosDataSourceProperties.getUsername()); } if (!StringUtils.isEmpty(nacosDataSourceProperties.getPassword())) { properties.setProperty(PropertyKeyConst.PASSWORD, nacosDataSourceProperties.getPassword()); } return properties; } @Override public void write(T value) throws Exception { lock.lock(); try { // 发布新配置 configService.publishConfig(nacosDataSourceProperties.getDataId(), nacosDataSourceProperties.getGroupId(), this.configEncoder.convert(value), ConfigType.JSON.getType()); } catch (Exception e) { throw e; } finally { lock.unlock(); } } @Override public void close() throws Exception { } }
上述只实现了数据配置更新与同步,我们还需要根据 Sentinel 的不用规则来区分具体是更新哪个文件,因此有下:
2.定义 SentinelNacosDataSourceHandler类
public class SentinelNacosDataSourceHandler implements SmartInitializingSingleton { private final SentinelProperties sentinelProperties; public SentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) { this.sentinelProperties = sentinelProperties; } //实现SmartInitializingSingleton 的接口后,当所有非懒加载的单例Bean 都初始化完成以后,Spring 的IOC 容器会调用该接口的 afterSingletonsInstantiated() 方法 @Override public void afterSingletonsInstantiated() { sentinelProperties.getDatasource().values().forEach(this::registryWriter); } private void registryWriter(DataSourcePropertiesConfiguration dataSourceProperties) { final NacosDataSourceProperties nacosDataSourceProperties = dataSourceProperties.getNacos(); if (nacosDataSourceProperties == null) { return; } final RuleType ruleType = nacosDataSourceProperties.getRuleType(); // 通过数据源配置的 ruleType 来注册数据源 switch (ruleType) { case FLOW: WritableDataSource> flowRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString); WritableDataSourceRegistry.registerFlowDataSource(flowRuleWriter); break; case DEGRADE: WritableDataSource
> degradeRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString); WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWriter); break; case PARAM_FLOW: WritableDataSource
> paramFlowRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString); ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWriter); break; case SYSTEM: WritableDataSource
> systemRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString); WritableDataSourceRegistry.registerSystemDataSource(systemRuleWriter); break; case AUTHORITY: WritableDataSource
> authRuleWriter = new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString); WritableDataSourceRegistry.registerAuthorityDataSource(authRuleWriter); break; default: break; } } }
3. Spring IOC 管理 SentinelNacosDataSourceHandler
@Configuration(proxyBeanMethods = false) @AutoConfigureAfter(SentinelAutoConfiguration.class) public class SentinelNacosDataSourceConfiguration { @Bean @ConditionalOnMissingBean public SentinelNacosDataSourceHandler sentinelNacosDataSourceHandler(SentinelProperties sentinelProperties){ return new SentinelNacosDataSourceHandler(sentinelProperties); } }
4. 配置文件
bootstrap.yml 中的配置文件内容如下:
spring: application: name: spring-cloud-sentinel-demo #微服务名称 cloud: nacos: config: #配置nacos配置中心地址 server-addr: 192.168.0.123:8847 username: nacos password: nacos file-extension: yml # 指定配置文件的扩展名为yml namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b
nacos 中微服务对应的配置文件内容如下:(也就是 application.yml ):
server: port: 8800 spring: application: name: spring-cloud-sentinel-demo #微服务名称 cloud: nacos: #配置nacos注册中心地址 discovery: server-addr: 192.168.0.123:8847 username: nacos password: nacos sentinel: transport: dashboard: 192.168.0.123:8091 datasource: flow-rules: #流控规则 nacos: server-addr: 192.168.0.123:8847 namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b username: nacos password: nacos dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP # 注意groupId对应Sentinel Dashboard中的定义 data-type: json rule-type: flow degrade-rules: #降级规则 nacos: server-addr: 192.168.0.123:8847 namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP data-type: json rule-type: degrade param-flow-rules: nacos: server-addr: 192.168.0.123:8847 namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b dataId: ${spring.application.name}-param-flow-rules groupId: SENTINEL_GROUP data-type: json rule-type: param-flow authority-rules: nacos: server-addr: 192.168.0.123:8847 namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b dataId: ${spring.application.name}-authority-rules groupId: SENTINEL_GROUP data-type: json rule-type: authority system-rules: nacos: server-addr: 192.168.0.123:8847 namespace: 6a7dbc5f-b376-41c6-a282-74ad4fd4829b dataId: ${spring.application.name}-system-rules groupId: SENTINEL_GROUP data-type: json rule-type: system
3. 测试
1. 在 Sentinel Dashboard 新建流控规则:
查看 Nacos 配置中心,在对应的 namespace 下多了一个配置文件:spring-cloud-sentinel-demo-flow-rules 因为在上述文件中指定了 flow-rules 数据源的 namespace 和 group :
查看此配置文件的详情可以看到:内容就是刚才流控规则的序列化内容:
综上,Sentinel Dashboard 新建的规则可以成功序列化到 Nacos 的配置中。
2. 在 Nacos 控制台修改对应的 count,在Sentinel Dashboard 查看是否同步显示:
修改前先查看Sentinel Dashboard 目前流控的阈值为2:
修改Nacos 中 spring-cloud-sentinel-demo-flow-rules 的配置,并发布:
修改后查看 Sentinel Dashboard 目前流控的阈值为3:
测试流控效果,已可以正常限流:
4. 其他规则也类似于流控规则
四、总结
最后附上这部分源码梳理图,可以结合上述内容一起理解。
猜你喜欢
- 17天前(万达酒店及度假村连续五年荣获“中国饭店集团60强”)万达酒店及度假村连续五年荣获“中国饭店集团60强”
- 17天前(七尚酒店百度百科)Lohkah七尚酒店首度开创充满新知的闽地研学旅程
- 17天前(福朋喜来登酒店宴会厅)福朋喜来登品牌亮相北部湾城市群 阳江中心福朋喜来登酒店开业
- 17天前(河南省文旅大会精神)2025河南省文化旅游发展大会新闻发布会在郑州召开
- 17天前(2025年“文化和自然遗产日”广东主会场活动举办)2025年“文化和自然遗产日”广东主会场活动举办
- 17天前(重庆恐龙化石遗址)重庆黔江恐龙化石抢救性发掘新闻发布会举行
- 17天前(新西兰“空降”上海:新西兰旅游局邀请你来“玩真的”!)新西兰“空降”上海:新西兰旅游局邀请你来“玩真的”!
- 17天前(澳涞坞是什么)从最美山庄到世界舞台:澳涞山庄见证世界十佳旅居城市评选
- 17天前(岭南东方大酒店)粤西成势 | 阳江阳春长兴岭南东方酒店正式签约,粤西文旅再添明珠
- 17天前(海南航空现况怎样)用一场直播找到市场扩张新渠道,海南航空做对了什么?
网友评论
- 搜索
- 最新文章
- (2020广州车展哈弗)你的猛龙 独一无二 哈弗猛龙广州车展闪耀登场
- (哈弗新能源suv2019款)智能科技颠覆出行体验 哈弗重塑新能源越野SUV价值认知
- (2021款全新哈弗h5自动四驱报价)新哈弗H5再赴保障之旅,无惧冰雪护航哈弗全民电四驱挑战赛
- (海南航空现况怎样)用一场直播找到市场扩张新渠道,海南航空做对了什么?
- (visa jcb 日本)优惠面面俱到 JCB信用卡邀您畅玩日本冰雪季
- (第三届“堡里有年味·回村过大年”民俗花灯会活动)第三届“堡里有年味·回村过大年”民俗花灯会活动
- (展示非遗魅力 长安启源助力铜梁龙舞出征)展示非遗魅力 长安启源助力铜梁龙舞出征
- (阿斯塔纳航空公司)阿斯塔纳航空机队飞机数量增至50架
- (北京香港航班动态查询)香港快运航空北京大兴新航线今日首航
- (我在港航“呵护”飞机 每一次安全着陆就是最好的荣誉)我在港航“呵护”飞机 每一次安全着陆就是最好的荣誉
- 热门文章