当前位置: 首页 > news >正文

Sentinel架构篇 - 10分钟带你看滑动窗口算法的应用

限流算法

以固定时间窗口算法和滑动时间窗口算法为例,展开两种限流算法的分析。

固定时间窗口算法

在固定的时间窗口内,设置允许固定数量的请求进入。如果超过设定的阈值就拒绝请求或者排队。

具体的,按照时间划分为若干个时间窗口,每个时间窗口里面的设置的请求数量的阈值都是相同的。一旦某个时间窗口内的请求数量达到阈值,就会拒绝新的请求或者进入排队状态。

缺点是无法计算跨相邻时间窗口的请求数量是否达到阈值。

滑动时间窗口算法

在固定时间窗口的基础上,时间窗口的起点和终点不再固定,而是随着时间推移而不断变化,但是每个时间窗口的长度(终点-起点)始终是固定的,也就是说整体会随着时间的推移而不断滑动。

但是每次时间窗口的移动,都需要重新统计请求数量,会有一些重叠区域重复计算的问题,因此可以对时间窗口进行更细粒度的划分,增加一些子时间窗口,即样本窗口。这样对时间窗口内部的请求数量的计算就会变成对相应的样本窗口内部的请求数量的计算,再求和。如果超过阈值,同样会被限流。

源码分析

以 Sentinel 内部的 LeapArray 的 currentWindow 方法为例,解析如何根据指定时间获取对应的样本窗口。

流程概述

1、将指定时间 / 时间窗口的长度(默认500ms),再 % 样本窗口总数量,得到所属的新的样本窗口对应的下标 n。

2、再通过指定时间 - 指定时间 % 时间窗口的长度,得到对应样本窗口的开始时间。

3、从缓存中获取指定下标 n 的旧的样本窗口,如果该样本窗口不存在,则进行创建并返回。

4、比较新样本窗口的开始时间 t1 与旧样本窗口的开始时间 t2,分为三种情况。

  • 如果 t1 = t2,说明新样本窗口与旧样本窗口是相同的,则返回旧样本窗口。
  • 如果 t1 > t2,说明旧样本窗口的状态滞后,则重置旧样本窗口的所有指标,再使用 LongAdder 计算某一指标并进行更新,最后返回更新后的样本窗口。
  • 如果 t1 < t2,说明时间发生了倒流(一般不会发生)则创建新的样本窗口并返回。

LeapArray

public WindowWrap<T> currentWindow(long timeMillis) {if (timeMillis < 0) {return null;}// 计算指定时间所属的样本窗口的下标int idx = calculateTimeIdx(timeMillis);// 计算指定时间所属的样本窗口的起始时间点long windowStart = calculateWindowStart(timeMillis);/** Get bucket item at given time from the array.** (1) Bucket is absent, then just create a new bucket and CAS update to circular array.* (2) Bucket is up-to-date, then just return the bucket.* (3) Bucket is deprecated, then reset current bucket and clean all deprecated buckets.*/while (true) {WindowWrap<T> old = array.get(idx);if (old == null) {/**     B0       B1      B2    NULL      B4* ||_______|_______|_______|_______|_______||___* 200     400     600     800     1000    1200  timestamp*                             ^*                          time=888*            bucket is empty, so create new and update** If the old bucket is absent, then we create a new bucket at {@code windowStart},* then try to update circular array via a CAS operation. Only one thread can* succeed to update, while other threads yield its time slice.*/WindowWrap<T> window = new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));if (array.compareAndSet(idx, null, window)) {return window;} else {Thread.yield();}} else if (windowStart == old.windowStart()) {/**     B0       B1      B2     B3      B4* ||_______|_______|_______|_______|_______||___* 200     400     600     800     1000    1200  timestamp*                             ^*                          time=888*            startTime of Bucket 3: 800, so it's up-to-date** If current {@code windowStart} is equal to the start timestamp of old bucket,* that means the time is within the bucket, so directly return the bucket.*/return old;} else if (windowStart > old.windowStart()) {/**   (old)*             B0       B1      B2    NULL      B4* |_______||_______|_______|_______|_______|_______||___* ...    1200     1400    1600    1800    2000    2200  timestamp*                              ^*                           time=1676*          startTime of Bucket 2: 400, deprecated, should be reset** If the start timestamp of old bucket is behind provided time, that means* the bucket is deprecated. We have to reset the bucket to current {@code windowStart}.* Note that the reset and clean-up operations are hard to be atomic,* so we need a update lock to guarantee the correctness of bucket update.** The update lock is conditional (tiny scope) and will take effect only when* bucket is deprecated, so in most cases it won't lead to performance loss.*/if (updateLock.tryLock()) {try {// 重置所有指标并计算PASS指标return resetWindowTo(old, windowStart);} finally {updateLock.unlock();}} else {Thread.yield();}} else if (windowStart < old.windowStart()) {// 注意:一般不会出现该情况,该情况属于时间倒流return new WindowWrap<T>(windowLengthInMs, windowStart, newEmptyBucket(timeMillis));}}
}

calculateTimeIdx

private int calculateTimeIdx(/*@Valid*/ long timeMillis) {// windowLengthInMs默认是500long timeId = timeMillis / windowLengthInMs;// array数组的长度默认是2return (int)(timeId % array.length());
}

计算指定时间所属的样本窗口的下标。

calculateWindowStart

protected long calculateWindowStart(/*@Valid*/ long timeMillis) {return timeMillis - timeMillis % windowLengthInMs;
}

计算指定时间所属的样本窗口的开始时间。

resetWindowTo

以 OccupiableBucketLeapArray 为例。

@Override
protected WindowWrap<MetricBucket> resetWindowTo(WindowWrap<MetricBucket> w, long time) {// 将windowStart设置为指定时间,即样本窗口的开始时间w.resetTo(time);// 获取样本窗口的统计数据MetricBucket borrowBucket = borrowArray.getWindowValue(time);if (borrowBucket != null) {// 重置所有指标w.value().reset();// 计算PASS指标w.value().addPass((int)borrowBucket.pass());} else {// 重置所有指标w.value().reset();}return w;
}

MetricBucket#reset

public MetricBucket reset() {for (MetricEvent event : MetricEvent.values()) {// 重置所有指标counters[event.ordinal()].reset();}// 初始化minRt属性initMinRt();return this;
}

MetricEvent 是一个枚举类,包括:PASS, BLOCK, EXCEPTION, SUCCESS, RT, OCCUPIED_PASS。

MetricBucket#initMinRt

private void initMinRt() {// 获取 csp.sentinel.statistic.max.rt 属性值(默认 5000),并初始化minRt属性this.minRt = SentinelConfig.statisticMaxRt();
}

MetricBucket#addPass

public void addPass(int n) {// 计算PASS指标add(MetricEvent.PASS, n);
}public MetricBucket add(MetricEvent event, long n) {// 底层使用LongAdder计算指标counters[event.ordinal()].add(n);return this;
}

相关文章:

Sentinel架构篇 - 10分钟带你看滑动窗口算法的应用

限流算法 以固定时间窗口算法和滑动时间窗口算法为例&#xff0c;展开两种限流算法的分析。 固定时间窗口算法 在固定的时间窗口内&#xff0c;设置允许固定数量的请求进入。如果超过设定的阈值就拒绝请求或者排队。 具体的&#xff0c;按照时间划分为若干个时间窗口&#…...

redis主从复制

<1> redis主从复制介绍&#xff1a; 首先来介绍一下什么是redis主从复制 Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中&#xff0c;当读写体量比较大的时候&#xff0c;服务端就很难承受…...

近期常见组件漏洞更新:

&#xff08;1&#xff09;mysql 5.7 在2023年1月17日&#xff0c;发布了到5.7.41版本 mysql 8.0 在2023年1月17日&#xff0c;发布了到8.0.32版本 MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ &#xff08;2&#xff09;Tomcat8在202…...

深度学习常用的激活函数总结

各种激活函数总结 目录一、sigmoid二、tanh![在这里插入图片描述](https://img-blog.csdnimg.cn/a0d92552edf8464db793fdd2f2b75cb5.png)三、ReLU系列1.原始ReLU2.ReLU改进&#xff1a;Leaky ReLU四、swish五、GeLU一、sigmoid 优点&#xff1a; 1.可以将任意范围的输出映射到 …...

Java编程问题top100---基础语法系列(二)

Java编程问题top100---基础语法系列&#xff08;二&#xff09;六、如何测试一个数组是否包含指定的值&#xff1f;简单且优雅的方法:自己动手写逻辑对象数组JDK 8 APIJDK 9 API Set.of()七、重写&#xff08;Override&#xff09;equlas和hashCode方法时应考虑的问题理论上讲&…...

网页打印与导出word实现在A4纸上相同效果

在工作中遇到这样一个需求&#xff0c;客户要求&#xff1a; 1、实现在浏览器中打印和导出到word中&#xff0c;要求浏览器打印出来的效果和word中打印的效果基本一致。2、打印的内容要自动分页&#xff0c;第一页的顶部有文件头&#xff0c;最后一页的底部有页尾。 这里记录一…...

备战英语6级——记录复习进度

开始记录—— 学习&#xff1a;如何记录笔记&#xff1f; 1&#xff1a;首先我认为&#xff1a;电脑打字比较适合我&#xff01; 2&#xff1a;先记笔记&#xff0c;再“填笔记”&#xff01; 记笔记就是一个框架&#xff0c;记录一个大概的东西。后面需要在笔记中&#xff0…...

实例10:四足机器人运动学逆解可视化与实践

实例10&#xff1a; 四足机器人运动学逆解单腿可视化 实验目的 了解逆运动学的有无解、有无多解情况。了解运动学逆解的求解。熟悉逆运动学中求解的几何法和代数法。熟悉单腿舵机的简单校准。掌握可视化逆向运动学计算结果的方法。 实验要求 拼装一条mini pupper的腿部。运…...

Elasticsearch7.8.0版本优化——路由选择

目录一、Elasticsearch 如何知道一个文档存放在哪个分片二、不带 routing 查询三、带 routing 查询一、Elasticsearch 如何知道一个文档存放在哪个分片 其实是通过这个公式来计算出来&#xff1a;shard hash(routing) % number_of_primary_shardsrouting 默认值是文档的 id&a…...

Go常量的定义和使用const,const特性“隐式重复前一个表达式”,以及iota枚举常量的使用

Go常量的定义和使用const,以及iota枚举常量的使用Go常量constGo中常量的定义和使用Go特性const,"隐式重复前一个表达式"iota 实现枚举常量Go常量const Go语言中的const整合了C语言中的宏定义常量&#xff0c;const只读变量枚举变量 绝大多数情况下&#xff0c;Go常…...

Git学习(1)pro git阅读

目录 目录&#xff1a; 1. 起步 2. Git 基础 3. Git 分支 4. 服务器上的 Git 5. 分布式 Git 第一章 1.3 Git是什么 1.6运行git前的配置 该开源图书网站 Git - Book (git-scm.com) 目录&#xff1a; 1. 起步 1.1 关于版本控制1.2 Git 简史1.3 Git 是什么&#xff1f;1…...

PHY自协商

1. 自协商定义 自动协商模式是端口根据另一端设备的连接速度和双工模式&#xff0c;自动把它的速度调节到最高的公共水平&#xff0c;即线路两端能具有的最快速度和双工模式。 自协商功能允许一个网络设备能够将自己所支持的工作模式信息传达给网络上的对端&#xff0c;并接受对…...

【大数据离线开发】8.2 Hive的安装和配置

8.3 Hive的安装和配置 安装模式&#xff1a; 嵌入模式 &#xff1a;不需要使用MySQL&#xff0c;需要Hive自带的一个关系型数据库&#xff1a;Derby本地模式、远程模式 ----> 需要MySQL数据库的支持 安装 hive 安装包 1、解压tar -zxvf apache-hive-2.3.0-bin.tar.gz -C…...

Capture Modules:车载网络报文捕获模块

&#xff08;以下所有图片均来源于Technica官网&#xff09; Technica Engineering的新一代硬件设备&#xff0c;即Capture Modules&#xff0c;提供了五种变体以涵盖不同带宽的车载以太网&#xff08;100BASE-T1和1000BASE-T1&#xff09;以及常见的IVN技术&#xff08;CAN、C…...

数据结构与算法系列之时间与空间复杂度

这里写目录标题算法的复杂度大O的渐进表示法实例分析空间复杂度每日一题算法的复杂度 衡量一个算法的好坏&#xff0c;一般 是从时间和空间两个维度来衡量的&#xff0c; 即时间复杂度和空间复杂度。 时间复杂度主要衡量一个算法的运行快慢&#xff0c; 空间复杂度主要衡量一个…...

Python代码使用PyQt5制作界面并封装

目录参考链接续&#xff1a;https://blog.csdn.net/yulinxx/article/details/93344163 若要对此程序进行封装&#xff0c;加个界面&#xff0c;然后制作成 EXE&#xff0c; 使用 PyQt5 制作界面&#xff0c;PyInstaller 进行封装成 EXE 可参考&#xff1a; Python制作小软件…...

【Node.js】MySQL数据库的第三方模块(mysql)

mysql安装操作MySQL数据库的第三方模块&#xff08;mysql&#xff09;通过第三方模块&#xff08;mysql2&#xff09;连接到MySQL数据库mysql插入数据mysql插入数据的便捷方式mysql更新数据mysql更新数据的便捷方式mysql删除数据安装操作MySQL数据库的第三方模块&#xff08;my…...

Docker中安装并配置单机版redis

1、使用docker安装redis 搜索Reis镜像&#xff0c;这里展示的是官方最新的镜像docker search redis 使用官方dockerhub搜索redis 2、选用常用的redis5.0作为安装的版本docker pull redis:5.0 3、运行redis容器的两种方式 3.1 不映射外部配置文件直接运行redis5.0镜像docker …...

模拟微信聊天-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)

【案例9-1】 模拟微信聊天 【案例介绍】 1.案例描述 在如今&#xff0c;微信聊天已经人们生活中必不可少的重要组成部分&#xff0c;人们的交流很多都是通过微信来进行的。本案例要求&#xff1a;将多线程与UDP通信相关知识结合&#xff0c;模拟实现微信聊天小程序。通过监…...

html2canvas将页面dom元素内容渲染成图片保存至本地

html2canvas:https://html2canvas.hertzen.com/configuration/ github:https://github.com/niklasvh/html2canvas 效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compa…...

前端进阶JS运行原理

JS运行原理 深入了解V8引擎原理 浏览器内核是由两部分组成的&#xff0c;以webkit为例&#xff1a; WebCore&#xff1a;负责HTML解析、布局、渲染等等相关的工作&#xff1b;JavaScriptCore&#xff1a;解析、执行JavaScript代码&#xff1b; 官方对V8引擎的定义&#xff1…...

Python识别二维码的两种方法(cv2)

在学习Python处理二维码的过程中&#xff0c;我们看到的大多是“用python生成酷炫二维码”、“用Python制作动图二维码”之类的文章。而关于使用Python批量识别二维码的教程&#xff0c;并不多见。所以今天我会给大家分享两种批量识别二维码的Python技巧&#xff01;pyzbar PI…...

用一个例子告诉你 怎样使用Spark中RDD的算子

目录 1. 前言 1.1 操作分类 1.2 语法知识 2. transformations 2.1 map 2.2 mapPartitions 2.3 flatMap 2.4 glom 2.5 groupBy 2.6 filter 2.7 sample 2.8 distinct 2.9 coalesce 2.10 repartition 2.11 sortBy 2.12 partitionBy 2.13 reduceByKey 2.14 gro…...

什么是跨域? 出现原因及解决方法

目录一、什么是跨域二、为什么有跨域问题&#xff1f;三、解决跨域问题的方案1.Jsonp2.nginx3.CORS3.1 什么是cors3.2 原理四、GateWay网关中实现跨域步骤一、什么是跨域 跨域&#xff1a;浏览器对于javascript的同源策略的限制 。 同源政策的目的&#xff0c;是为了保证用户…...

低代码系统能够解决哪些痛点?

低代码系统能够解决哪些痛点&#xff1f;如果用4句话去归纳&#xff0c;低代码开发可以解决以下问题—— 为企业提供更高的灵活性&#xff0c;用户可以突破代码的限制自主开发业务应用&#xff1b;通过减少对专业软件开发人员的依赖&#xff0c;公司可以快速响应市场上的新业务…...

华为OD机试题,用 Java 解【两数之和绝对值最小】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…...

AcWing算法提高课-3.1.1热浪

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 题目传送门点这里 题目描述 德克萨斯纯朴的民众们这个夏天正在遭受巨大的热浪&#xff01;&#xff01;&#xff01; 他们的德克萨斯长角牛吃起来不错&#xff0c;可是它们并不是很擅长生产富…...

华为OD机试题【最差产品奖】用 C++ 编码,速通 (2023.Q1)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明最差产…...

NFT市场大战:Blur市场地位可持续吗?

在战胜无数虚张声势的挑战者之后&#xff0c;OpenSea终于迎来了一个实力雄厚的竞争对手&#xff0c;已威胁到它的市场主导地位。opensea是什么&#xff1f;参考《NFT&#xff0c;区块链的产物之一&#xff0c;了解NFT交易平台Opensea》 继成功的空投之后&#xff0c;Blur并没有…...

初识CSS

1.CSS语法形式CSS基本语法规则就是:选择器若干属性声明由选择器选择一个元素,其中的属性声明就作用于该元素.比如:<body><p>这是一个段落</p><!-- style可以放在代码的任意地方 --><style>p{/* 将字体颜色设置为红色 */color: red;}</style&g…...

网站开发站点的文件夹/网络营销的方法有哪些?

如何选择合适的图表类型和使用场景 以QUICK BI 来介绍常见基本图形以及应用场景...

wordpress播放百度云/谷歌搜索为什么用不了

路径参数 获取请求头中的指定参数,或者全部参数 获取拼接url中的参数 获取cookie中的参数,拿指定名称的,或者全拿 获取请求体 设置请求域 矩阵变量 矩阵变量生效...

公司主营网站开发怎么做账/旺道seo营销软件

有 1000 个一模一样的瓶子&#xff0c;其中有 999 瓶是普通的水&#xff0c;有一瓶是毒药。任何喝下毒药的生物都会在一星期之后死亡。现在&#xff0c;你只有 10 只小白鼠和一星期的时间&#xff0c;如何检验出哪个瓶子里有毒药&#xff1f; 参考答案&#xff1a; 【1】根据2^…...

有后台的网站模板/百度云服务器

三、三维互联网的定位在营销前有几个要点要做&#xff1a;第一对品牌和规模进行定位&#xff1b;第二要进行市场细分&#xff1b;第三经营定位&#xff08;就是对你的三维互联网虚拟平台的档次进行定位&#xff09;。在进行营销之前一定要把这些功课做足&#xff0c;搞明白。我…...

聚合页做的比较好的教育网站/seo技巧

在EditPlus上利用正则替换一些繁杂的代码 比如想用System.out.println();输出这些代码&#xff0c;而且不想一个个ctrl c, ctrl v&#xff0c;可以试试利用EditPlus配合正则给这些代码换上。 "a".matches(".");"aa".matches("aa");&qu…...

一个完美的网站怎么做/整合营销沟通

在使用TX2的过程中&#xff0c;我想要对一些代码进行调试&#xff0c;但是在Tx2上使用gdb进行调试&#xff0c;可视化效果比较差&#xff0c;于是想要使用嵌入式系统中的交叉编译方式。在主机上对Tx2进行刷机后&#xff0c;会自动在主机上安装Nsight软件。用这个软件可以对Tx2进…...