在前面的學習過程當中,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裏面設置一個斷點,你會發現,當發佈配置以後,這邊立刻就會進來,而後執行其餘的邏輯,到此爲止整個流程結束。