Sentinel Client: 整合Apollo規則持久化

在前面的學習過程當中,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

擴展的常見方式有推和拉兩種模式:微信

  • 拉模式:客戶端主動向某個規則管理中心按期輪詢拉取規則,這個規則中心能夠是 RDBMS、文件,甚至是 VCS 等。這樣作的方式是簡單,缺點是沒法及時獲取變動;
  • 推模式:規則中心統一推送,客戶端經過註冊監聽器的方式時刻監聽變化,好比使用 NacosApollo、Zookeeper 等配置中心。這種方式有更好的實時性和一致性保證。

今天咱們主要是講如何使用 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裏面設置一個斷點,你會發現,當發佈配置以後,這邊立刻就會進來,而後執行其餘的邏輯,到此爲止整個流程結束。

歡迎加入個人知識星球,一塊兒交流技術,免費學習猿天地的課程(http://cxytiandi.com/course

PS:目前星球中正在星主的帶領下組隊學習Sentinel,等你哦!

微信掃碼加入猿天地知識星球

猿天地

相關文章
相關標籤/搜索