在前面的学习过程当中,Sentinel 的规则,也就是咱们以前定义的限流规则,是经过代码的方式定义好的。这是初始化时须要作的事情,Sentinel 提供了基于API的方式修改规则:git
FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则 DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则 SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则 AuthorityRuleManager.loadRules(List<AuthorityRule> rules); // 修改受权规则
当咱们接入了控制台后,能够经过控制台进行规则的动态修改,问题是当应用程序重启后规则信息就会恢复到初始化的阶段,也就是说后面修改的值会丢失,由于规则信息都是存储在应用的内存中。github
为了解决这个问题Sentinel 提供了DataSource 扩展的功能,官方推荐经过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变动,流程以下:json
扩展的常见方式有推和拉两种模式:微信
今天咱们主要是讲如何使用 Apollo 来配置规则进行持久化,Apollo是携程开源的配置中心,很是好用app
Github地址:https://github.com/ctripcorp/...ide
在个人书中也有对Apollo使用的详细介绍,等出版了再通知你们。学习
首先集成须要的依赖:this
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-apollo</artifactId> <version>1.4.1</version> </dependency>
而后建立 ApolloDataSource 并将其注册至对应的 RuleManager 上便可。好比:spa
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<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName, flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { })); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); }
到此为止配置就结束了,详细的解释我都写了注释哈。官方文档也是这么写的,问题是若是你刚接触会一头雾水的,为何?code
你不知道在Apollo中怎么配置啊,咱们讲的就是说能够用Apollo来做为存储,持久化规则,那么规则怎么配置就须要咱们本身去想。
我也是经过看源码才知道怎么去配置的,带着你们一块儿来看源码吧!
主要就是new ApolloDataSource这里,参数都是经过这里传进去的
public ApolloDataSource(String namespaceName, String flowRulesKey, String defaultFlowRuleValue, Converter<String, T> parser) { 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<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName, flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { }));
重点是ource -> JSON.parseObject(source, new TypeReference<List<FlowRule>>()这行,这不就是转换成List<FlowRule>吗,真相呼之欲出了,也就是在Apollo中配置的就是List<FlowRule>的json格式就行。
咱们配置一个试试看:
flowRules = [{"grade":1,"count":11,"resource":"HelloWorld"}]
点击保存而且发布,能够在initializeConfigChangeListener里面设置一个断点,你会发现,当发布配置以后,这边立刻就会进来,而后执行其余的逻辑,到此为止整个流程结束。