摘要:这样做的方式是简单,缺点是无法及时获取变更推模式规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用等配置中心。
在前面的学习过程中,Sentinel 的规则,也就是我们之前定义的限流规则,是通过代码的方式定义好的。这是初始化时需要做的事情,Sentinel 提供了基于API的方式修改规则:
FlowRuleManager.loadRules(Listrules); // 修改流控规则 DegradeRuleManager.loadRules(List rules); // 修改降级规则 SystemRuleManager.loadRules(List rules); // 修改系统规则 AuthorityRuleManager.loadRules(List rules); // 修改授权规则
当我们接入了控制台后,可以通过控制台进行规则的动态修改,问题是当应用程序重启后规则信息就会恢复到初始化的阶段,也就是说后面修改的值会丢失,因为规则信息都是存储在应用的内存中。
为了解决这个问题Sentinel 提供了DataSource 扩展的功能,官方推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更,流程如下:
扩展的常见方式有推和拉两种模式:
拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Apollo、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。
今天我们主要是讲如何使用 Apollo 来配置规则进行持久化,Apollo是携程开源的配置中心,非常好用
Github地址:https://github.com/ctripcorp/...
在我的书中也有对Apollo使用的详细介绍,等出版了再通知大家。
首先集成需要的依赖:
com.alibaba.csp sentinel-datasource-apollo 1.4.1
然后创建 ApolloDataSource 并将其注册至对应的 RuleManager 上即可。比如:
private static void loadRules() { // Apollo 中的应用名称,自己定义的 String appId = "SampleApp"; // Apollo 的地址 String apolloMetaServerAddress = "http://localhost:8080"; System.setProperty("app.id", appId); System.setProperty("apollo.meta", apolloMetaServerAddress); // 指定环境 System.setProperty("env", "DEV"); // Apollo 的命名空间 String namespaceName = "application"; // 限流规则的Key, 在Apollo中用此Key String flowRuleKey = "flowRules"; // 限流规则的默认值 String defaultFlowRules = "[]"; // 注册数据源 ReadableDataSource> flowRuleDataSource = new ApolloDataSource<>(namespaceName, flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference >() { })); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); }
到此为止配置就结束了,详细的解释我都写了注释哈。官方文档也是这么写的,问题是如果你刚接触会一头雾水的,为什么?
你不知道在Apollo中怎么配置啊,我们讲的就是说可以用Apollo来作为存储,持久化规则,那么规则怎么配置就需要我们自己去想。
我也是通过看源码才知道怎么去配置的,带着大家一起来看源码吧!
主要就是new ApolloDataSource这里,参数都是通过这里传进去的
public ApolloDataSource(String namespaceName, String flowRulesKey, String defaultFlowRuleValue, Converterparser) { super(parser); Preconditions.checkArgument(!Strings.isNullOrEmpty(namespaceName), "Namespace name could not be null or empty"); Preconditions.checkArgument(!Strings.isNullOrEmpty(flowRulesKey), "FlowRuleKey could not be null or empty!"); this.flowRulesKey = flowRulesKey; this.defaultFlowRuleValue = defaultFlowRuleValue; this.config = ConfigService.getConfig(namespaceName); initialize(); RecordLog.info(String.format("Initialized rule for namespace: %s, flow rules key: %s", namespaceName, flowRulesKey)); }
这边就是对传入的参数赋值,然后看下面这行:
this.config = ConfigService.getConfig(namespaceName);
这就是通过命名空间去Apollo中获取配置,获取完后就执行初始化
private void initialize() { initializeConfigChangeListener(); loadAndUpdateRules(); }
initializeConfigChangeListener是初始化配置的监听器,当配置发生修改时会进入该监听器,也就是说在这个监听器里需要监听配置的修改,然后更新规则
private void initializeConfigChangeListener() { config.addChangeListener(new ConfigChangeListener() { @Override public void onChange(ConfigChangeEvent changeEvent) { ConfigChange change = changeEvent.getChange(flowRulesKey); //change is never null because the listener will only notify for this key if (change != null) { RecordLog.info("[ApolloDataSource] Received config changes: " + change.toString()); } loadAndUpdateRules(); } }, Sets.newHashSet(flowRulesKey)); }
loadAndUpdateRules就是更新规则的逻辑了
private void loadAndUpdateRules() { try { T newValue = loadConfig(); if (newValue == null) { RecordLog.warn("[ApolloDataSource] WARN: rule config is null, you may have to check your data source"); } getProperty().updateValue(newValue); } catch (Throwable ex) { RecordLog.warn("[ApolloDataSource] Error when loading rule config", ex); } }
那么配置是怎么来的呢,请看loadConfig
@Override public T loadConfig() throws Exception { return loadConfig(readSource()); } public T loadConfig(S conf) throws Exception { T value = parser.convert(conf); return value; }
readSource就是获取我们配置的flowRulesKey的值,那么配置其实就是一个字符串,然后下面通过Json转换
public String readSource() throws Exception { return config.getProperty(flowRulesKey, defaultFlowRuleValue); }
我们再返过来看看注册的代码:
// 注册数据源 ReadableDataSource> flowRuleDataSource = new ApolloDataSource<>(namespaceName, flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference >() { }));
重点是ource -> JSON.parseObject(source, new TypeReference>()这行,这不就是转换成List
我们配置一个试试看:
flowRules = [{"grade":1,"count":11,"resource":"HelloWorld"}]
点击保存并且发布,可以在initializeConfigChangeListener里面设置一个断点,你会发现,当发布配置之后,这边马上就会进来,然后执行其他的逻辑,到此为止整个流程结束。
欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course) PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74014.html
摘要:在之前的两篇教程中我们分别介绍了如何将的限流规则存储到和中。本文以存储为例,下一篇介绍的改在示例。但是由于考虑到与的结合使用,略作修改。 在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中。同时,在文末的思考中,我都指出了这两套整合方案都存在一个不足之处:不论采用什么配置中心,限流规则都只能通过Nacos界面或Apollo界面来完成修改才能...
摘要:前面我们都是直接通过集成的依赖,通过编码的方式配置规则等。对于集成到中阿里已经有了一套开源框架,就是用于将一系列的框架成功的整合到中。但这也是在学习过程中遇到的一个问题,还是得通过调试源码的方式去发现问题的原因。 前面我们都是直接通过集成sentinel的依赖,通过编码的方式配置规则等。对于集成到Spring Cloud中阿里已经有了一套开源框架spring-cloud-alibaba...
摘要:改造背景前面我们讲解了如何对接来持久化限流的规则,对接后可以直接通过的后台进行规则的修改,推送到各个客户端实时生效。因此推送规则正确做法应该是配置中心控制台控制台配置中心数据源,而不是经数据源推送至配置中心。 改造背景 前面我们讲解了如何对接Apollo来持久化限流的规则,对接后可以直接通过Apollo的后台进行规则的修改,推送到各个客户端实时生效。 但还有一个问题就是Sentinel...
摘要:上一篇我们介绍了如何通过的配置功能来存储限流规则。第六步启动应用。深入思考在使用存储规则配置的时候与存储一样,对于控制台这些数据是只读的,也就是说控制台中修改规则仅存在于服务的内存中,不会修改中的配置值,重启后恢复原来的值。 上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则。Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba...
摘要:所以,在整合了做规则存储之后,需要知道在下面两个地方修改存在不同的效果控制台中修改规则仅存在于服务的内存中,不会修改中的配置值,重启后恢复原来的值。控制台中修改规则服务的内存中规则会更新,中持久化规则也会更新,重启后依然保持。 通过上一篇《使用Sentinel实现接口限流》的介绍,相信大家对Sentinel已经有了初步的认识。在Spring Cloud Alibaba的整合封装之下,接...
阅读 1269·2023-04-26 00:10
阅读 2410·2021-09-22 15:38
阅读 3691·2021-09-22 15:13
阅读 3456·2019-08-30 13:11
阅读 627·2019-08-30 11:01
阅读 3004·2019-08-29 14:20
阅读 3181·2019-08-29 13:27
阅读 1671·2019-08-29 11:33