sentinel源码:最简单的qps限流是怎么做的?滑动窗口算法原理

参考

首先当然要先看下官方文档知道大概原理,然后再细看

构建demo走源码

在这里参考官网demo好了

pom中引入:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.7.2</version>
</dependency>

main函数

package com.vava.sentinel;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;

/**
 * @author Steve
 * Created on 2020-07
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        initFlowRules();
        while (true) {
            Thread.sleep(10);
            Entry entry = null;
            try {
                entry = SphU.entry("HelloWorld");
                /*您的业务逻辑 - 开始*/
                System.out.println("hello world");
                /*您的业务逻辑 - 结束*/
            } catch (BlockException e1) {
                /*流控逻辑处理 - 开始*/
                System.out.println("block!");
                /*流控逻辑处理 - 结束*/
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }
        }
    }

    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

可以看到输出:
有block的,有helloworld的
在这里插入图片描述

开始提问题看源码

自定义的rule,写在哪了?

从demo中看,是由FlowRuleManager把规则load进来的:
在这里插入图片描述

点进去看,应该是注册了一堆listener然后告知他们配置有更新
在这里插入图片描述
看不到啥有用信息,先放一放,看下真正跑起来的时候是如何加载规则的

如何加载规则?

demo中是通过新建
entry = SphU.entry(“HelloWorld”);

点进去:
在这里插入图片描述

对资源名称“HelloWorld”包装了一下,然后跳进这个entry函数

在这里插入图片描述
找一下处理链(责任链模式),这里是DefaultProcessorSlotChain

然后chain.entry再跳进去:

在这里插入图片描述
一大段注释说明用context的名字而不是resource的名字作为key去查规则。

在这个最简单的demo里,没有context只有resource。所以以resource的名字作为key去查。发现也是null

然后创建了一个DefaultNode,然后把这个新的node放进去map里了。

然后走到最后一行,最后调了SPI了,会在每个SPI的责任链里做不同的处理。
在这里插入图片描述

在这里插入图片描述

从官网我们得知,这个责任链的顺序是:
在这里插入图片描述

我们就跟着责任链一步一步的走

我比较关心的、比较核心的应该是监控统计StatisticSlot 、流量控制FlowSlot,我们可以重点看下这两块的代码

StatisticSlot

在这里插入图片描述

addPassRequest(count) 看着比较可疑 跳进去来到一个ArrayMetric
在这里插入图片描述

这里的data就是官网介绍的高性能数组LeapArray
在这里插入图片描述
至于怎么高性能我们先leave it be吧,按照官网的说法就是用滑动窗口的方法来统计指标
在这里插入图片描述
这个获取当前窗口的算法的注释有点牛皮。。

先看下官网这个图:大概知道获取个window是什么意思:
在这里插入图片描述
假设我们设定好了窗口大小是1000ms,然后sampleCount=5,传入一个当前时间910,怎么知道当前的窗口是200-1000呢?当前时间是1001的时候,怎么知道窗口已经滑动到400-1200呢?

我们做一个假设,当前时间永远要在最后一格里,想象这个当前时间带着整个窗口往右移动:(910在最后一格子,1001也在最后一个格子)

抽象一下,我们需要根据输入: 窗口大小:1000ms, sampleCount:5 , 当前时间:910;输出:windowStart=0。这个算法怎么写!这个静下心来想想应该不难对吧。假设让你写你会怎么写?

每个采样的格子大小是:1000ms/5=200ms。

910/200200=4200=800(当前时间所在格子的左区间)

1001/200200=5200=1000(当前时间所在格子的左区间)

然后根据假设,我们永远认为当前格子在最后一个格子,所以800-4200=0;1000-4200=200,这就算出了当前窗口的左区间。
在这里插入图片描述
函数的入参是当前时间,出参是WindowWrap

算法肯定跟我们上面说的类似。
int idx = calculateTimeIdx(timeMills)
在这里插入图片描述
当前时间/采用间隔 910/200=4, 取模4%5=4,idx=4
在这里插入图片描述
windowStart = 910-910%200=910-110=800

然后根据之前这个槽里的时间 做一下比较 决定是否要挪动窗口 具体原理跟我们上面的算法很类似,可以看那个漂亮的注释理解一下:
在这里插入图片描述
如果发现槽是空,则直接新建一个东西放进去
如果发现槽不空,里面的东西的windowStart跟算出来的windowStart相等,说明还在这个时间间隔里,直接返回就行
如果发现槽里的东西过期了,那就需要更新一把,拖着window走。

FlowSlot

在这里插入图片描述

上来就跳进去checkFlow,检查有没有超过限流规则

在这里插入图片描述

ruleProvider,是一个函数,输入String(resourceName),输出 规则列表 Collection<FlowRule>
然后逐条检查canPassCheck,一旦有没过检查的就抛出异常。
在这里插入图片描述

这么一取就取出来了

单机模式下一直跳到这个canPass
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值