桥泰

导航

 

 

 


限流规则有多种,他要根据你的规则和策略选择不同节点?
限流模式:直接、关联、链路
Node selectedNode = selectNodeByRequesterAndStrategy(rule, context, node);
selectedNode
【直接、关联】获取的ClusterNode
【链路】获取的DefaultNode

rule.getRater().canPass(selectedNode, acquireCount, prioritized);
DefaultController、WarmUpController【快速失败】直接、关联,滑动窗口算法
RateLimiterController 就是【排队等待】模式,漏桶算法


com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController#canPass(com.alibaba.csp.sentinel.node.Node, int, boolean)(Node node, int acquireCount, boolean prioritized) {
int curCount = this.avgUsedTokens(node);
if ((double)(curCount + acquireCount) > this.count) {
curCount已经使用了多少 + 要求多少,如果大于 流控阈值,那么返回false
否则返回true

this.avgUsedTokens(node);// 是获取滑动窗口的请求量之和,小区间累加之和
谁给每个小区间计数呢?StatisticSlot
com.alibaba.csp.sentinel.slots.statistic.StatisticSlot#entry
node.addPassRequest(count);
super.increaseThreadNum();
this.clusterNode.increaseThreadNum();

com.alibaba.csp.sentinel.node.StatisticNode#addPassRequest
this.rollingCounterInSecond.addPass(count);// 找到当前这个请求在哪个时区(窗口),给这个时区+1,WindowWrap就是这个小时区,找到了这个小时区+1
this.rollingCounterInMinute.addPass(count);// 预热、平均运算

this.rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);// 数组统计:滑动窗口分成几份(样本数量),滑动窗口的时间间隔是多长
维护很多的区间,区间用数组维护,每个区间就是一个格子,有无数个区间,就是无数个格子
区间越小,限流越精准,限流效果越平滑
this.data.currentWindow();给对应窗口计数
ArrayMetric类维护了一个LeapArray<MetricBucket> data,滑动窗口的数组,就是小区间MetricBucket

例子:
环形数组,存储滑动窗口数据,并进行统计。
一个滑动窗口最多包含2个区间,1秒,1个区间500ms,统计一个请求来了,要统计qps,其实就是统计这个请求所在滑动窗口的qps
真正有效的样本区间,其实就是当前请求进来时离它最近的两个样本区间
打个比方:
1秒,2个区间
当走到2号格子是,当前有效样本区间,其实就是,1号、2号格子有效。至于环形覆盖的问题,其实没啥影响!!!
滑动窗口+环形数组,就可以表示无穷多个区间。


com.alibaba.csp.sentinel.slots.statistic.base.LeapArray#currentWindow(long)
int idx = this.calculateTimeIdx(timeMillis);计算角标区间格子
除出来多少份
long timeId = timeMillis / (long)this.windowLengthInMs;
将这些多少份,依次铺开到环形数组上,得到一个下标值
return (int)(timeId % (long)this.array.length());


long windowStart = this.calculateWindowStart(timeMillis);
格子的起始时间
timeMillis - timeMillis % (long)this.windowLengthInMs;
用当前时间 减去 超出格子区间的那一部分,就是起始时间


WindowWrap<T> old = (WindowWrap)this.array.get(idx);
if (old == null) {
格子是空的,我是第一个,那么创建一个添加进去,把窗口放入到角标位置

} else if (windowStart < old.windowStart()) {
// 环形数组已经填满,也就是新窗口要覆盖旧窗口
window = this.resetWindowTo(old, windowStart);
// 重置了一下窗口的开始时间
总结:
旧窗口不存在,创建
旧窗口存在,并且开始时间和新计算的一样,直接返回当前窗口
旧窗口存在,但是新计算的窗口开始时间比旧窗口的开始时间更新,那么更新旧窗口的开始时间

((MetricBucket)wrap.value()).addPass(count); 然后对窗口 +1

 

com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController#avgUsedTokens
node.curThreadNum() : (int)node.passQps();
第一个是做隔离用的,第二个是做限流
com.alibaba.csp.sentinel.node.StatisticNode#passQps
this.rollingCounterInSecond.pass() / this.rollingCounterInSecond.getWindowIntervalInSec(); 通过的总数量/通过的总时间:秒

com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric#pass
先对齐好滑动窗口值和数据
在统计滑动窗口区间内的请求数

this.isWindowDeprecated(timeMillis, windowWrap)
windowWrap.windowStart() < time - (long)this.intervalInMs 就是过期了的时间区间

或者另外一种解释
time - windowWrap.windowStart() > (long)this.intervalInMs
当前时间1250ms - 0 > 1000ms 真,就是过期
1250ms - 500 > 1000ms 假,还没有过期


com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController#canPass(Node, int, boolean)
最后判断当前滑动窗口的数量+当前需要的请求数 > count 阈值,如果大于,那么返回false,进行限流,否则不进行限流

 

 


posted on 2025-06-11 17:24  桥泰  阅读(15)  评论(0)    收藏  举报