zoukankan      html  css  js  c++  java
  • Sentinel Client: 整合Apollo规则持久化

    在前面的学习过程中,Sentinel 的规则,也就是我们之前定义的限流规则,是通过代码的方式定义好的。这是初始化时需要做的事情,Sentinel 提供了基于API的方式修改规则:

    FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
    DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则
    SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则
    AuthorityRuleManager.loadRules(List<AuthorityRule> rules); // 修改授权规则
    

    当我们接入了控制台后,可以通过控制台进行规则的动态修改,问题是当应用程序重启后规则信息就会恢复到初始化的阶段,也就是说后面修改的值会丢失,因为规则信息都是存储在应用的内存中。

    为了解决这个问题Sentinel 提供了DataSource 扩展的功能,官方推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更,流程如下:

    扩展的常见方式有推和拉两种模式:

    • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
    • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 NacosApollo、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

    今天我们主要是讲如何使用 Apollo 来配置规则进行持久化,Apollo是携程开源的配置中心,非常好用

    Github地址:https://github.com/ctripcorp/apollo

    在我的书中也有对Apollo使用的详细介绍,等出版了再通知大家。

    首先集成需要的依赖:

    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-apollo</artifactId>
        <version>1.4.1</version>
    </dependency>
    

    然后创建 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<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName,
                flowRuleKey, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
            }));
            FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
    

    到此为止配置就结束了,详细的解释我都写了注释哈。官方文档也是这么写的,问题是如果你刚接触会一头雾水的,为什么?

    你不知道在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>()这行,这不就是转换成List吗,真相呼之欲出了,也就是在Apollo中配置的就是List的json格式就行。

    我们配置一个试试看:

    flowRules = [{"grade":1,"count":11,"resource":"HelloWorld"}]
    

    点击保存并且发布,可以在initializeConfigChangeListener里面设置一个断点,你会发现,当发布配置之后,这边马上就会进来,然后执行其他的逻辑,到此为止整个流程结束。

    欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

    PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!

    微信扫码加入猿天地知识星球

    猿天地

  • 相关阅读:
    js事件
    增量
    文本文件输入(忽略行)
    当数据库的字段为date类型时候
    枚举的使用
    input输入框用el对数字格式化
    图片提交按钮各浏览器不兼容问题
    js对数字的校验
    时间控件
    ymPrompt消息提示组件4.0版 演示及使用简介
  • 原文地址:https://www.cnblogs.com/yinjihuan/p/10634675.html
Copyright © 2011-2022 走看看