sentinelzkdatabase源码解析(限流部分)

1 项目背景

sentinel没有提供规则持久化的线上实现,只是提供了实现思路。除了api方式外,其他方案都需要添加比较多的代码修改,包括dashboard源码和应用。为避免如此繁琐的行为,采用API+PUSH混合方式实现sentinel zookeeper的持久化。
在这里插入图片描述

2 github项目链接

https://github.com/chlInGithub/sentienlzkdatabase

3 应用启动阶段

3.1 初始化zkClient

CuratorFrameworkFactory.newClient的第二个参数retryPolicy,是指在连接ZK服务过程中重新连接的策略.在它的实现类ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries)中,baseSleepTimeMs参数代表两次连接的等待时间,maxRetries参数表示最大的尝试连接次数。
在这里插入图片描述

3.2 调用zookeeperDataSource4Flow方法

在这里插入图片描述

3.2.1 ZookeeperDataSource实例化

在这里插入图片描述
在这里插入图片描述

3.2.1.1 initZookeeperListener(serverAddr, authInfos)方法

在这里插入图片描述

在这里插入图片描述

3.2.1.1.1 添加节点监听nodeChanged

在这里插入图片描述
内部调用loadConfig方法,完成从zk读取数据源,并进行格式转换成List类型。

在这里插入图片描述
然后加载到内存中:getProperty().updateValue(newValue);
在这里插入图片描述

3.2.1.1.2 NodeCache实例化及添加监听

在这里插入图片描述
NodeCache作用:使用节点数据作为本地缓存使用。这个类可以对节点进行监听,能够处理节点的增删改事件,数据同步等。 还可以通过注册自定义监听器来更细节的控制这些数据变动操作。

NodeCache实例化:
this.nodeCache = new NodeCache(this.zkClient, this.path);

NodeCache 添加监听:
this.nodeCache.getListenable().addListener(this.listener, ZookeeperDataSource.pool);

ZookeeperDataSource.pool:
public static final ExecutorService pool = new ThreadPoolExecutor(8, 16, 0, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue(100), new NamedThreadFactory(“sentinel-zookeeper-ds-update”),
new ThreadPoolExecutor.DiscardOldestPolicy());

3.2.1.2 loadInitialConfig() 方法
3.2.1.2.1 loadConfig()方法

调用loadConfig()方法,首先调用readSource()方法从zookeeper里面加载配置信息。
在这里插入图片描述
在这里插入图片描述
configInfo信息:

[
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 5, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 20, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 3, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 2, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }
]

将数据进行转换并返回
在这里插入图片描述
convert实际调用的方法:
在这里插入图片描述
在这里插入图片描述

3.2.1.2.2 更新内存配置信息

在这里插入图片描述
在这里插入图片描述
调用DynamicSentinelProperty的updateValue方法,遍历监听器更新本地配置,但由于此时监听器数量为0,所以不会进行配置更新的操作。限流规则将赋值给value,而此时的listeners属性(Set<PropertyListener> listeners = new CopyOnWriteArraySet()),大小仍然为0。
在这里插入图片描述
在这里插入图片描述

3.2.2 FlowRuleManager.register2Property(flowRuleDataSource.getProperty())

3.2.2.1 flowRuleDataSource.getProperty()

获取DynamicSentinelProperty的实例:
在这里插入图片描述

3.2.2.2 初始化FlowRuleManager

在这里插入图片描述
1.调用currentProperty.addListener(LISTENER);此处的LISTENER为FlowRuleManager.FlowPropertyListener。如下图所示:
在这里插入图片描述
addListener方法内部做了2步操作,1是将当前的监听器FlowRuleManager.FlowPropertyListener添加到set集合中
在这里插入图片描述
2是调用listener.configLoad(this.value)方法,对此监听器进行配置加载。但由于value未初始化,为null。所以此步骤相当于没做任何操作。
在这里插入图片描述

3.2.2.3 register2Property方法

在这里插入图片描述
1.从currentProperty里面把FlowRuleManager.FlowPropertyListener这个监听器移除:
currentProperty.removeListener(LISTENER);
在这里插入图片描述
2.对当前传进来的实例DynamicSentinelProperty,添加监听:property.addListener(LISTENER);
在这里插入图片描述
此方法主要做了2步操作,1是将当前FlowRuleManager.FlowPropertyListener这个监听器添加到set集合中
在这里插入图片描述
2是调用listener.configLoad(this.value)方法,完成配置加载到本地:
在这里插入图片描述
3.将property赋值给currentProperty
在这里插入图片描述
在这里插入图片描述

3.2.3 modifyFlowRuleManager(zkClient, zookeeperDataSource, path)

在这里插入图片描述

3.2.3.1 ZKPropertyListener初始化

在这里插入图片描述

3.2.3.2 zookeeperDataSource.getProperty().addListener(flowPropertyListener)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
调用ZKPropertyListener的configLoad方法
在这里插入图片描述

4 控制台修改配置

在这里插入图片描述

4.1 触发节点更新nodeChanged 方法

在这里插入图片描述

4.1.1 loadConfig方法(同3.2.1.2.1)

在这里插入图片描述

4.1.2 更新内存配置信息

在这里插入图片描述
在这里插入图片描述

4.1.2.1 更新DynamicSentinelProperty实例的value属性

调用DynamicSentinelProperty的updateValue方法。此方法首先是把最新的限流规则赋值给了value:
在这里插入图片描述

4.1.2.2 遍历调用监听器的configUpdate方法

其次获取DynamicSentinelProperty实例的监听器listeners:ZKPropertyListener以及FlowRuleManager.FlowPropertyListener
在这里插入图片描述
然后依次调用其configUpdate方法,将最新的配置加载到内存中:

4.1.2.2.1 FlowRuleManager.FlowPropertyListener:

在这里插入图片描述

4.1.2.2.2 ZKPropertyListener:

在这里插入图片描述
在这里插入图片描述

4.1.2.2.2.1 initPath:

创建存储规则的path,此处的path为 /SENTINEL-RULE/apiGateway/FLOW-DATA
在这里插入图片描述

4.1.2.2.2.2 getLockPath:

此处的lockPath为:
/SENTINEL-RULE/apiGateway/FLOW-DATA/lockHashCode-1656893730
在这里插入图片描述

4.1.2.2.2.3 gainLock:

确保path数据只被一个app node负责更新
在这里插入图片描述

4.1.2.2.2.4 避免重复修改:

判断新值和旧值是否会相等,相等则直接返回,避免重复修改
在这里插入图片描述

4.1.2.2.2.5 最新的规则,保存到zk:

先获取最新的规则数据:
在这里插入图片描述
此处的data为:

[
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 5, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 1, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 20, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }, 
    {
        "clusterConfig": {
            "acquireRefuseStrategy": 0, 
            "clientOfflineTime": 2000, 
            "fallbackToLocalWhenFail": true, 
            "resourceTimeout": 2000, 
            "resourceTimeoutStrategy": 0, 
            "sampleCount": 10, 
            "strategy": 0, 
            "thresholdType": 0, 
            "windowIntervalMs": 1000
        }, 
        "clusterMode": false, 
        "controlBehavior": 0, 
        "count": 3, 
        "grade": 1, 
        "limitApp": "default", 
        "maxQueueingTimeMs": 500, 
        "resource": "HelloWorld", 
        "strategy": 0, 
        "warmUpPeriodSec": 10
    }
]

最新的数据保存到zk:
在这里插入图片描述

4.1.2.2.2.6 releaseLock:

释放lock:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值