本文内容主要讲解“ASP中使用滑动窗口限制电流问题的实例分析。网芯”。感兴趣的朋友不妨看看。本文介绍的方法简单、快速、实用。让边肖带你学习“ASP中使用滑动窗口限流问题的实例分析。网芯”!
滑动窗口算法用于处理时间段内请求的不均匀分布,能够更准确地处理流量变化。众所周知的应用场景是TCP协议的流量控制,但今天我们要讲的是服务限流场景中的应用。
算法原理
假设业务需要每秒限制电流100次。我们先来看看固定窗口算法的两个问题:
00-1010如下图所示,仅第1秒和第2秒的请求数不超过100,因此固定窗口算法不会触发电流限制。但前一秒最后500 ms的请求数加上第二秒前500ms的请求数超过100,此时可能会给系统带来危害,使用固定窗口算法时无法检测到这种情况。
漏检
对于漏检的问题,可以说可以将时间窗口设置为500ms,将限流阈值设置为50。然后看下图,除了第二个计数周期超过50触发限流外,前一个和后一个计数周期的请求都是正常的,甚至没有超过阈值的50%。可能第二个计数周期的情况太特殊,一天之内不会出现第二次。如果不影响系统,你能适应吗?不要。固定窗口算法此时会过于死板。
那么滑动窗口如何解决这两个问题呢?我们先来看看图片:
如上图所示:
滑动窗口的时间跨度为1秒,每个小计数周期的时间跨度为500 ms,这里滑动窗口包含2个小计数周期。
随着时间的推移,滑动窗口中包含的小计数周期将在500ms内向前移动,但它始终包含两个小计数周期。
在判断是否限制电流时,需要将当前滑动窗口中包含的两个小计数周期的计数值相加。
与固定窗口计数算法相比,滑动窗口可以有效减少漏检。如上图所示,当滑动窗口移动到500-1500毫秒时,如果总数超过100,就会触发限流。滑动窗口不会在0-1000毫秒和1000-2000毫秒触发电流限制。即使小周期的计数值超过阈值的一半,但总数不超过100,也不会限制电流,可以应对罕见的突发流量情况。
从分析中可以看出,滑动窗口划分的小周期越多,检测越准确,但是用于跟踪的计数越多,使用的内存和计算就越多。
00-1010这里有两种实现方法:进程内内存滑动窗口算法和基于Redis的滑动窗口算法。
00-1010这里介绍一种高性能的方法,利用数组实现滑动窗口,这是循环队列的特例,如下图所示:
假设滑动窗口需要5个小的计数周期,初始化一个长度为5的整数数组,数字代表数组中的哪个元素。
我们知道队列有头有尾。我们从队列的头部获取数据,并将数据插入队列的尾部。括号中的数字表示队列中的元素。
当滑动窗口向前移动时,队列的尾部向右移动一位,队列的头部也向右移动一位。
将队列的尾部和队列的头部向右移动可能会溢出数组,所以让它们返回到数组的起始位置,即图中数组的第一个位置。
关于这个算法的详细介绍,可以看这篇文章:如何用数组实现滑动窗口。
00-1010基于Redis也可以使用类似循环队列的方法,比如定义5 KVs作为数组的5个元素。但是,我之前用了更直观的方式来实现。每个小计数周期都会创建一个KV,同时设置一个绝对超过滑动窗口时间跨度的到期时间,这样未使用的小计数周期就不会一直占用内存。在判断是否触发限流时,累加这些小滑窗的计数值就足够了。当然,在实际实现中,我们需要改进一些细节,比如如何找到这些小的计数周期。会有很多方案,可以保存,也可以临时计算。
这些操作逻辑可以封装在Lua脚本中。因为Lua脚本在热地Redis执行时也是原子操作
s的限流计数在分布式部署时天然就是准确的。
应用算法
这里以限流组件 FireflySoft.RateLimit 为例,实现ASP.NET Core中的滑动窗口限流。
1、安装Nuget包
有多种安装方式,选择自己喜欢的就行了。
包管理器命令:
Install-Package FireflySoft.RateLimit.AspNetCore
或者.NET命令:
dotnet add package FireflySoft.RateLimit.AspNetCore
或者项目文件直接添加:
<ItemGroup> <PackageReference Include="FireflySoft.RateLimit.AspNetCore" Version="2.*" /> </ItemGroup>
2、使用中间件
在Startup中使用中间件,演示代码如下(下边会有详细说明):
public void ConfigureServices(IServiceCollection services) { ... app.AddRateLimit(new InProcessSlidingWindowAlgorithm( new[] { // 构造函数有两个参数:滑动窗口的时间长度、小计数周期的时间长度 new SlidingWindowRule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1)) { ExtractTarget = context => { // 提取限流目标 return (context as HttpContext).Request.Path.Value; }, CheckRuleMatching = context => { // 判断当前请求是否需要限流处理 return true; }, Name="sliding window limit rule", LimitNumber=100, // 限流阈值,这里即5秒最多100次请求 } }) ); ... } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseRateLimit(); ... }
如上需要先注册服务,然后使用中间件。
注册服务的时候需要提供限流算法和对应的规则:
-
这里使用进程内固定窗口算法InProcessSlidingWindowAlgorithm,还可以使用RedisSlidingWindowAlgorithm,需要传入一个Redis连接。两种算法都支持同步和异步方法。
-
限流阈值是100,限流滑动窗口是5秒,小计数周期是1秒。
-
ExtractTarget用于提取限流目标,这里是每个不同的请求Path。如果有IO请求,这里还支持对应的异步方法ExtractTargetAsync。
-
CheckRuleMatching用于验证当前请求是否限流。如果有IO请求,这里还支持对应的异步方法CheckRuleMatchingAsync。
-
默认被限流时会返回HttpStatusCode 429,可以在AddRateLimit时使用可选参数error自定义这个值,以及Http Header和Body中的内容。
基本的使用就是上边例子中的这些了。
如果还是基于传统的.NET Framework,则需要在Application_Start中注册一个消息处理器RateLimitHandler,算法和规则部分都是共用的,具体可以看Github上的使用说明:https://github.com/bosima/FireflySoft.RateLimit
FireflySoft.RateLimit 是一个基于 .NET Standard 的限流类库,其内核简单轻巧,能够灵活应对各种需求的限流场景。
其主要特点包括:
-
多种限流算法:内置固定窗口、滑动窗口、漏桶、令牌桶四种算法,还可自定义扩展。
-
多种计数存储:目前支持内存、Redis两种存储方式。
-
分布式友好:通过Redis存储支持分布式程序统一计数。
-
限流目标灵活:可以从请求中提取各种数据用于设置限流目标。
-
支持限流惩罚:可以在客户端触发限流后锁定一段时间不允许其访问。
-
动态更改规则:支持程序运行时动态更改限流规则。
-
自定义错误:可以自定义触发限流后的错误码和错误消息。
-
普适性:原则上可以满足任何需要限流的场景。
到此,相信大家对“ASP.NET Core中使用滑动窗口限流的问题举例分析”有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/141692.html