草庐IT

13. 滑动时间窗口算法概念原理

91猿说编程 2023-11-29 原文

1. 时间窗介绍

在之前的学习中,我们已经学习完成了Sentinel源码的Node关系、责任链调用,那么这节课我们就要学习Sentinel核心源码中的一个非常重要的算法“滑动时间窗口算法”,也就是结构图中的WindowLeapArray,它为Sentinel提供当前时间的数据支撑, 如当前QPS,请求数,异常数等。

2. 固定时间窗口算法

要学习滑动窗口,我们先要学习时间窗口算法,以循序渐进的方式了解滑动窗口,时间窗口算法也可以称之为:固定时间窗算法

概念:固定时间窗口计数器算法思想:在固定的时间窗口内,可以允许固定数量的请求进入。超过数量就拒绝或者排队,等下一个时间段进入。

那我们来看图分析:

具体分析一下:

  1. 将当前的时间分为10t大小的几个时间窗
  2. 规则是阈值为100个请求数,每个时间窗里面的请求数量不能超过阈值100
  3. 10t到16t进入请求10个,16t到20t进入请求50个,总数60个请求,没有超过阈值100
  4. 20t到26t进入请求60个,26t到30t进入请求20个,总数80个请求,没有超过阈值100
  5. 30t到40t之间进入请求120个,超过阈值20个,所以20个请求无法进入

存在问题:

16t到26t之间也是10t大小的一个时间窗,但跨了两个固定的时间窗,问题是请求总数为110,超过阈值,这种固定时间窗无法处理这部分超出的请求,所以解决办法就是使用滑动时间窗

3. 滑动时间窗算法

使用滑动时间窗的主要原因是虽然以上提到超出阈值的范围跨了两个时间窗,但是超过的请求书的范围是10t,且实际上我们要清楚,我们系统限流的目的是要在任意时间窗都要能应对突然的流量暴增,如果使用以上的算法,就会造成在16t和26t之间的请求无法限流,严重会导致服务雪崩。

要解决的话,我们就需要使用滑动时间窗算法,具体原理如下:

滑动时间窗限流算法解决了固定时间窗限流算法的问题。其没有划分固定的时间窗起点与终点,而是将每一次请求的到来时间点作为统计时间窗的终点,起点则是终点向前推时间窗长度的时间点。这种时间窗称为“滑动时间窗”

看图分析

此图中我们可以分析中,实际上当前的时间窗不再是固定的,而是可以从时间的起始位置一直向右滑动

这样的话就可以解决固定时间窗带来的问题,其原理就是:

  1. 当前时间窗口为滑动窗口,可以从左向右按照时间顺序进行滑动,并且大小为10t,同时此时的阈值为100
  2. 红色线的位置进入一个请求,此时想要判断这个请求是否能够正常通过,就要看当前滑动窗口中的请求数量是否达到阈值,如果当前没有达到阈值100,就可以正常通过,但是如果一旦超过阈值,就会被进行限流。

存在问题

但是此时滑动时间窗还是有问题的,问题就是会出现大量的重复统计,造成系统效率下降,如下图所示:

在此图中我们就可以看出,这个蓝色的区域就是重复统计的区域,也就是说每一次移动时间窗口,都需要重新统计重复区域的请求数量,从而导致浪费大量的系统资源。

解决办法

想要解决以上的问题,我们就需要更加细粒度话的计算,增加多个子时间窗口:样本窗口

4. 优化滑动时间窗算法-样本窗口

为了解决滑动时间窗算法因为每次滑动都需要重复统计滑动前的一部分数据的问题,这个问题很致命,特别是作为一个流控组件来说,不应该影响整体系统的效率。所以需要改进, 在改进方案中,引入了样本窗口来解决问题。

样本窗口概念:

  1. 样本窗口的长度必须小于滑动窗口长度,如果等于滑动窗口长度就会退化成固定时间窗口
  2. 一般滑动窗口长度是样本窗口的整数倍,比如:4*样本窗口=1个滑动窗口
  3. 每个样本窗口在到达终点时间时,会统计本样本窗口中的流量数据并且记录下来。
  4. 当一个请求达到时,会统计当前请求时间点所在的样本窗口中的流量数据,然后在获取当前请求时间的样本窗口以外的同一个滑动窗口中的样本窗口的统计数据,进行求和,如果没有超出阈值,则通过,否则就会被限流

原理图被限流的情况:

此时会被流控,因为因为样本窗口的请求数加起来再加上当前时间窗的10个请求数已经到阈值100了,所以新过来的请求就会被流控

原理图不被限流的情况:

此时这个请求将不会被限流,因为本次请求的时间的对应的样本窗口只有5个请求加上之前重复的样本窗口统计的流量值,没有超过阈值100,所以本次请求会通过。

有关13. 滑动时间窗口算法概念原理的更多相关文章

  1. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  2. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  3. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  4. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  5. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

    运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

  6. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  7. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  8. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  9. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  10. ruby-on-rails - gem install rmagick -v 2.13.1 错误 Failed to build gem native extension on Mac OS 10.9.1 - 2

    我已经通过提供MagickWand.h的路径尝试了一切,我安装了命令工具。谁能帮帮我?$geminstallrmagick-v2.13.1Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingrmagick:ERROR:Failedtobuildgemnativeextension./Users/ghazanfarali/.rvm/rubies/ruby-1.8.7-p357/bin/rubyextconf.rbcheckingforRubyversion>=1.8.5...yescheckingfor/

随机推荐