高可用之限流-06-slide window 滑动窗口 sentinel 源码

news2025/5/23 19:35:47

限流系列

开源组件 rate-limit: 限流

高可用之限流-01-入门介绍

高可用之限流-02-如何设计限流框架

高可用之限流-03-Semaphore 信号量做限流

高可用之限流-04-fixed window 固定窗口

高可用之限流-05-slide window 滑动窗口

高可用之限流-06-slide window 滑动窗口 sentinel 源码

高可用之限流-07-token bucket 令牌桶算法

高可用之限流 08-leaky bucket漏桶算法

高可用之限流 09-guava RateLimiter 入门使用简介 & 源码分析

sentinel 构建滑动时间窗口

上文介绍过通过调用LeadArray的currentWindow方法返回时间窗口,下面来仔细分析。

public WindowWrap<T> currentWindow() {
    //参数是当前时间
    return currentWindow(TimeUtil.currentTimeMillis());
}

public WindowWrap<T> currentWindow(long time) {
    // 1、根据当前时间,算出该时间的timeId,timeId就是在整个时间轴的位置
    long timeId = time / windowLengthInMs;
    // 2、据timeId算出当前时间窗口在采样窗口区间中的索引idx
    int idx = (int)(timeId % array.length());
    // 3、根据当前时间算出当前窗口应该对应的窗口开始时间time,以毫秒为单位
    time = time - time % windowLengthInMs;
    //4、循环判断直到获取到一个当前时间窗口
    while (true) {
        //5、根据索引idx,在采样窗口数组中取得一个时间窗口old
        WindowWrap<T> old = array.get(idx);
        //6、如果old为空,说明该时间窗口还没有创建、则创建一个时间窗口,并将它插入到array的第idx个位置
        if (old == null) {
            //创建时间窗口,参数:窗口大小,开始时间,桶(保存统计值)
            WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
             // 通过CAS将新窗口设置到数组中去
            if (array.compareAndSet(idx, null, window)) {
                return window;
            } else {
                Thread.yield();
            }
          //7、如果当前窗口的开始时间time与old的开始时间相等,那么说明old就是当前时间窗口,直接返回old
        } else if (time == old.windowStart()) { 
            return old;
        } 
          //8、如果当前窗口的开始时间time大于old的开始时间,则说明old窗口已经过时了,将old的开始时间更新为最新值:time,下一个循环中在第7步返回
        else if (time > old.windowStart()) {
            if (updateLock.tryLock()) {
                try {
                    // if (old is deprecated) then [LOCK] resetTo currentTime.
                    // 重置窗口,重新设置窗口的开始时间,以及把统计值重置
                    return resetWindowTo(old, time);
                } finally {
                    updateLock.unlock();
                }
            } else {
                Thread.yield();
            }
        //这个条件不可能存在,time是当前的时间
        } else if (time < old.windowStart()) {
            // Cannot go through here.
            return new WindowWrap<T>(windowLengthInMs, time, newEmptyBucket());
        }
    }
}

以上就是创建时间窗口的核心的代码了,解释都在代码上面。

分析后可以发现:获取时间窗口原理就是找到当前时间所在的窗口,若窗口不存在则创建,若窗口过时了则重置。

窗口分析

通过分析 rollingCounterInSecond 的监控指标来分析时间窗口,

private transient volatile Metric rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT,
        IntervalProperty.INTERVAL);

在StatisticNode类中,rollingCounterInSecond创建可以发现windowLengthInMs:时间窗口是500ms,

intervalInSec:时间区间是1s。所以在时间区间是1s内最多只有两个时间窗口,每个窗口长度是500ms;

时间窗口的创建过程如图:

image

1、现在假设当前时间是2018-12-15 14:30:00,对应毫秒是:1544855400000ms,所以timeId = 1544855400000 / 500为:3089710800,对应的idx为0,窗口开始时间time为 time - time % windowLengthInMs还是1544855400000;

2、初始化的时候old为空,所以创建了一个window;

3、倘若过了300ms后,time为1544855400700,这个时候old就是先前窗口了,就会直接返回old窗口:currentWindow;

4、时间继续往前走,又过了400ms后,如图:

image

5、这个时候获取到的timeId为3089710801,对应的idx=为3089710801%2为1,窗口开始时间time为 1544855400500;

6、由于是新的时间窗口,old为空,则重新创建。

7、倘若过了400ms,time为1544855401100:现在得到idx时0,这个时候old是有值的,但是old的windowStart小于time的StartTime,所以需要重置idx0窗口。

8、以此类推:随着时间的流逝,时间窗口也在变化,但是窗口只会在初始化的过程中创建两次,后面若窗口过期了则是重置。

核心流程

1、根据当前时间,算出该时间的timeId,timeId就是在整个时间轴的位置

2、据timeId算出当前时间窗口在采样窗口区间中的索引idx

3、根据当前时间算出当前窗口应该对应的窗口开始时间time,以毫秒为单位

4、循环判断直到获取到一个当前时间窗口

5、根据索引idx,在采样窗口数组中取得一个时间窗口old

如果old为空,说明该时间窗口还没有创建、则创建一个时间窗口,并将它插入到array的第idx个位置

如果当前窗口的开始时间time与old的开始时间相等,那么说明old就是当前时间窗口,直接返回old

如果当前窗口的开始时间time大于old的开始时间,则说明old窗口已经过时了,将old的开始时间更新为最新值:time; 。

参考资料

限流技术总结

固定窗口和滑动窗口算法了解一下

Sentinel之滑动时间窗口设计(二)

限流滑动窗口

限流算法之固定窗口与滑动窗口

限流--基于某个滑动时间窗口限流

【限流算法】java实现滑动时间窗口算法

谈谈高并发系统的限流

漏铜令牌桶

漏桶算法&令牌桶算法理解及常用的算法

流量控制算法——漏桶算法和令牌桶算法

Token Bucket 令牌桶算法

华为-令牌桶算法

简单分析Guava中RateLimiter中的令牌桶算法的实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二维码:理解二维码 / 生成二维码 / 小程序支持哪种类型的二维码 / 小程序识别GS1码

一、理解二维码 1.1、概念 二维码&#xff08;2-dimensional bar code&#xff09;&#xff0c;又称二维条码&#xff0c;最早发源于日本&#xff0c;它是用某种特定的几何图形按一定规律在平面&#xff08;二维方向上&#xff09;分布的黑白相间的图形记录数据符号信息的&am…

10月15日 -- 11月15日 ,参与《人工智能导论》学习打卡赢B站大会员

一、活动参与地址 点击链接进行活动报名>>>https://momodel.cn/classroom/course/detail?id6173911eab37f12b14daf4a8&activeKeyinfo&srcbef3adb478 二、活动详情 进入链接点击报名&#xff0c;仅需每天参与吴超老师的《人工智能导论》打卡活动&#xff0…

day11-SpringMVC

一、SpringMVC 1.SpringMVC流程分析 2.各种注解 3.接收请求参数 3.1 简单类型 3.2 对象类型 3.3 数组类型 3.4 集合类型 3.5 日期类型 3.6 json参数类型 3.7 路径参数 二、统一异常处理 三、Restful

一个月学会Java 第16天 注解和异常处理

Day16 注解和异常处理 为什么一定要标注是元注解呢&#xff0c;这个原因其实非常的简单&#xff0c;因为注解现在还不能写&#xff0c;想要使用注解达到SpringMVC和SpringBoot的等级需要使用反射&#xff0c;但是反射我们现在还不会&#xff0c;所以就先讲讲最基本的元注解。 第…

MOS管的电路应用

MOS管的电路应用 MOS管的选型参考 1、MOS管类型 一般选择增强型NMOS管&#xff0c;同等工艺条件下&#xff0c;导通电阻Ron更小&#xff0c;发热更低&#xff0c;允许通过的电流更大&#xff0c;型号也更多。 2、Vgs电压 需要考虑开启电压&#xff0c;驱动电压&#xff0c;极…

每日一刷——10.14——括号匹配(手写栈来实现)

栈与队列题目 第一题 题目 问题描述】设计一个算法判别一个算术表达式的圆括号是否正确配对 【输入形式】一个以为结尾的算术表达式 【输出形式】若配对&#xff0c;则输出圆括号的对数&#xff1b;否则输出no 【样例输入】 (ab)/(cd) 【样例输出】 2 【样例说明】共有两对括…

带隙基准Bandgap电路学习(三)

一、导入器件到版图中 从原理图中导入器件&#xff1a; Connectivity——>Generate——>All From Source I/O Pins暂不添加&#xff0c;后面自己画 PR&#xff08;Primary Region&#xff09;Boundary: 通常是用来定义芯片设计中某些关键区域的轮廓&#xff0c;比…

揭秘数字时代的安全守护者:深入探索RSA加密算法的奥秘

目录 引言 一、什么是RSA&#xff1f; 二、RSA 的基本原理 三、RSA 加密的基本步骤 1、加密过程 2、解密过程 四、RSA例子 五、RSA 的特点 六、RSA 的安全性 七、RSA 的实际应用 总结 引言 在当今的信息化社会&#xff0c;数据的安全性和隐私保护已…

外包干了两年,女朋友跟别人跑了

在这个瞬息万变的IT行业&#xff0c;不进则退的道理&#xff0c;我算是深刻体会到了。作为一名本科生&#xff0c;21年通过校招&#xff0c;我幸运地踏入了广州某知名软件公司的大门&#xff0c;成为了一名功能测试工程师。那时的我&#xff0c;满怀激情与梦想&#xff0c;以为…

Neuromnia是一家创新的AI平台用Llama为自闭症护理领域带来全新解决方案

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Linux——Harbor(容器镜像 管理项目)

镜像拉取存在一定的问题&#xff0c;出现原因在于&#xff1a; 使用官方公共仓库中的镜像。 拉取的镜像&#xff0c;主要保存在一下仓库中&#xff1a; docker.io //Docker hub 最大的官方维护的公共镜像仓库&#xff0c;一般都会提供所有项目的最新版镜像&#xff0c;镜像…

SIGformer: Sign-aware Graph Transformer for Recommendation

SIGformer: Sign-aware Graph Transformer for Recommendation&#xff08;Sigir24&#xff09; 摘要 在推荐系统中&#xff0c;大多数基于图的方法只关注用户的正面反馈&#xff0c;而忽略了有价值的负面反馈。将正反馈和负反馈结合起来形成一个带符号的图&#xff0c;可以更…

【AI论文精读5】知识图谱与LLM结合的路线图-P2

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI大项目】【AI应用】 P1 4 知识图谱增强的LLMs 大语言模型&#xff08;LLMs&#xff09;在许多自然语言处理任务中取得了令人期待的结果。然而&#xff0c;LLMs因缺乏实用知识和在推理过程中容易产生事实性错误而受到…

数据类型、变量和运算符

数据类型 数据类型分为基本数据类型和引用数据类型&#xff1b; 基本数据类型 无论是32位系统还是64位系统&#xff0c;数据类型所占的字节数都不会变 &#xff1b;整形和浮点型都是带有符号的&#xff1b;整型默认int&#xff0c;浮点型默认double&#xff1b; 整型 字节型…

图文深入理解java对象从创建到回收都经历了什么

1. 前言&#xff1a; 每个java对象都是有生命周期的&#xff0c;就像一个人的生命一样&#xff0c;从孕育到出生到成长变老最后由归于自然。笔者认为&#xff0c;Java对象的整个生命周期可以分为两个大的阶段&#xff1a;即创建阶段和运行阶段&#xff08;包含对象的回收和消亡…

19009 后缀表达式

### 思路 1. **输入处理**&#xff1a;读取输入的后缀表达式&#xff0c;去掉末尾的符号。 2. **使用栈计算后缀表达式**&#xff1a; - 遍历表达式中的每个字符。 - 如果是数字&#xff0c;压入栈中。 - 如果是运算符&#xff0c;从栈中弹出两个数字进行运算&#xf…

若依前后端分离版本el-select下拉框字典如何设置默认值。

在若依前后端分离框架中&#xff0c;如何给下拉框设置默认值&#xff0c;刚入门的小伙伴&#xff0c;可能会不知道如何去做。 本章教程&#xff0c;主要以用户管理模块中的添加用户举例说明如何设置用户性别默认值为男。 解决思路 首先&#xff0c;我们需要找到打开新增页面的方…

解锁机器学习的新维度:元学习的算法与应用探秘

引言 在机器学习快速发展的今天&#xff0c;元学习&#xff08;Meta-Learning&#xff09;作为一种新兴的方法论&#xff0c;受到了越来越多的关注。元学习的主要目标是使模型能够在面对新任务时迅速适应&#xff0c;通常只需极少的样本。这一能力在现实应用中尤为重要&#x…

linux点灯驱动实验实现

1.用字符串实现LED灯驱动编写 LED灯连接到的是GPIO1_IO03口上&#xff0c;所以我们只需要初始化这个引脚时钟&#xff0c;配置这个引脚和电器属性&#xff0c;我们就可以通过寄存器对LED进行控制。 2.内存映射 与STM32等芯片不同的是&#xff0c;linux系统对引脚地址操作不是…

光平面标定代码

本篇文章主要给出光平面标定代码&#xff0c;鉴于自身水平所限&#xff0c;如有错误&#xff0c;欢迎批评指正。&#xff08;欢迎进Q群交流&#xff1a;874653199&#xff09; 数据分为棋盘格数据和激光条数据&#xff0c;激光条数据为在第22个位姿至第26个位姿下打在棋盘格标定…