FireflySoft.RateLimit 使用
限流处理器
使用FireflySoft.RateLimit首先需要创建一个限流处理器RateLimitProcessor的实例,然后用它来过滤每一个请求。创建RateLimitProcessor的实例,至少需要提供两个信息:被限流的请求类型、限流算法和规则。其它还有限流计数持久化方式、限流错误信息,如果不提供会使用默认值。这里先不展开,后边会详细介绍它们。创建RateLimitProcessor需要采用构造器模式,如果你使用ASP.NET Core应该很熟悉,如果没什么印象打开Program.cs就可以看到了。为了提高效率,这个限流处理器一般会统一放在某个过滤器中,这个过滤器在ASP.NET中可以是一个消息处理器,在ASP.NET Core中一般就是一个中间件。为了方便集成,FireflySoft.RateLimit已经提供了一个基于ASP.NET的消息处理器和一个基于ASP.NET Core的中间件,通过Github和Nuget都可以很方便的找到他们,Github上还提供了演示程序.
被限流请求类型
被限流请求类型就是需要被限制的业务请求的类型,在ASP.NET中他可能是HttpRequestMessage,在ASP.NET Core中它可能是HttpContext,在其它业务中它可能是你自定义的一个类型XXXRequest。被限流请求类型很重要,因为不同的业务可能使用不同的请求类型,而限流处理程序需要从当前请求中提取或关联到限流目标,明确请求类型才能确定提取方法,否则对请求进行限制将无所适从
限流算法和规则
FireflySoft.RateLimit提供了四种常见的限流算法:固定窗口、滑动窗口、漏桶、令牌桶。固定窗口相对最简单,无论是算法的时间复杂度还是分布式环境实现难度都比较有优势,如果需求是在较短的时间内进行限制,比如每秒限制多少次,使用这种算法是最合适的。但是实际场景中请求在时间分布中可能不太均匀,时多时少,根据需求的不同,可能需要选择其它三种限流算法,这里不做说明了,网上已经有很多的场景选择说明。 初始化限流算法还需要提供对应的限流规则,因为不同的算法往往需要不同的参数,这里很难对不同的算法提供完全统一的限流规则,不过这些规则确实是有共同设置项的,比如限流锁定时间、目标提取方法、是否应用限流处理的判断方法等。 以上文【使用方法】中的限流代码为例,做一些介绍:
-
FixedWindowAlgorithm是此限流组件提供的固定窗口限流算法。
-
FixedWindowRateLimitRule是此限流组件提供的固定窗口限流规则类型;
-
HttpContext是业务中需要限制的请求类型,这里是Http请求上下文类型;
-
StatWindow是固定窗口的大小,是一个时间跨度;
-
LimitNumber是限流值,在StatWindow时间内请求数超过它就会触发限流;
-
LockSeconds是触发限流后的锁定时间,此时间内请求都会被阻止,不需要锁定时可以不设置;
-
ExtractTarget传递一个方法用于从请求中提取限流目标,这里是用户的每一个请求路径;
-
CheckRuleMatching传递一个方法用于检查当前请求是否需要限流检查,这里return true代表所有请求都要经过限流检查。
这里有两个比较有意思的设置:ExtractTarget
和CheckRuleMatching
,他们共同作用,让用户可以完全自由的定制自己限流的目标和条件,不固定是IP、ClientId或者Url。其它算法规则中每个设置项的含义可以通过其注释了解到。 如果这几个算法还不能满足要求,可以通过实现IRateLimitAlgorithm来定义一个新的算法。
计数持久化方式
FireflySoft.RateLimit中的限流计数目前支持保存在内存或者Redis中,也可以通过实现IRateLimitStorage来定义一个新的存储器。 对于只需要部署一份的程序,绝大部分情况下使用内存就够了;但是如果限流的时间窗口比较长,比如1小时限制300次,重启就会丢失计数,这可能是个风险,此时使用Redis会比较合适。 对于需要部署多份的程序,如果请求是基本均匀的,并且在每个部署之间的分配也是均匀的,那么使用内存存储器也未尝不可,将总的限流数平均分配在每一个部署中,只要有一个部署触发限流,其它部署很大几率上也会触发限流。但是对于需要部署多份的情况,采用更持久的Redis方式才是稳妥的。 相比内存访问,Redis访问需要网络交互,这会造成一定的性能损失,访问量很大时也会产生拥堵,不过也可以将请求分散到多个Redis的方式进行缓解;同时分布式环境下数据一致性的实现难度更大,即使使用Redis,比如限流处理中必然会涉及的各种时间,不同节点之间的时间不可能绝对一致,越短的时间窗口协调难度越大。因此使用滑动窗口、漏桶、令牌桶等分布式实现难度较大的算法时,需要注意时间单位的设置.
限流错误信息
限流错误信息是触发限流时限流检查结果中附带的信息,目前每个限流处理器允许设置一个统一的RateLimitError,方便业务侧进行统一处理。默认限流错误Code是429,Message为null。你也可以不使用这个定义的值,根据当前限流目标和限流规则构造自己的错误信息
限流锁定
限流锁定是触发限流时的惩罚性处理。FireflySoft.RateLimit通过设置限流规则中的LockSeconds,定义触发限流后的锁定时间,此时间内的请求都会被认定触发限流规则,而不被允许通过;如果不需要锁定忽略这个设置就可以了
如上图所示,时间单位是1秒,阈值是3。
-
第1秒3个请求,不会触发限流;
-
第2秒1个请求,不会触发限流;
-
第3秒4个请求,这一秒的前3个请求正常处理,第4个请求触发限流,会被拒绝处理。
-
后续第4秒、第5秒不会触发限流,所有请求正常处理。
Core、AspNet、Middleware 3种
Github 源码地址
GitHub - bosima/FireflySoft.RateLimit: It is a rate limiting library based on .Net standard.
Project | Descriptioin |
---|---|
FireflySoft.RateLmit.Core | FireflySoft.RateLmit的算法、规则、持久化和其它核心代码。 |
FireflySoft.RateLimit.AspNet | 为基于 .NET Framework的ASP.NET提供的限流组件。 |
FireflySoft.RateLimit.AspNetCore | ASP.NET Core限流中间件。 |
FireflySoft.RateLimit.Core.UnitTest | Unit test for FireflySoft.RateLimit.Core. |
FireflySoft.RateLimit.Core.BenchmarkTest | Benchmark test for FireflySoft.RateLimit.Core. |
samples/console | FireflySoft.RateLmit.Core sample program. |
samples/aspnet | FireflySoft.RateLimit.AspNet sample program. |
samples/aspnetcore | FireflySoft.RateLimit.AspNetCore sample program. |
samples/aspnetcore6 | FireflySoft.RateLimit.AspNetCore with .NET6 sample program. |
ASP.NET Core 使用方法:
1、Install Nuget Package Package Manager: Install-Package FireflySoft.RateLimit.AspNetCore Or .NET CLI: dotnet add package FireflySoft.RateLimit.AspNetCore
Use Middleware 使用方法:
public void ConfigureServices(IServiceCollection services) { ...
services.AddRateLimit(new InProcessFixedWindowAlgorithm( new[] { new FixedWindowRule() { ExtractTarget = context => { return (context as HttpContext).Request.Path.Value; }, CheckRuleMatching = context => { return true; }, Name="default limit rule", LimitNumber=30, StatWindow=TimeSpan.FromSeconds(1) } }));...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ...
app.UseRateLimit();...
}
ASP.NET
1、Install Nuget Package:
Install-Package FireflySoft.RateLimit.AspNet
2、Register MessageHandler
Open Global.asax.cs, the following code adds the rate limit message handle:
protected void Application_Start() { ...
GlobalConfiguration.Configuration.MessageHandlers.Add( new RateLimitHandler( new Core.InProcessAlgorithm.InProcessFixedWindowAlgorithm( new[] { new FixedWindowRule() { ExtractTarget = context => { return (context as HttpRequestMessage).RequestUri.AbsolutePath; }, CheckRuleMatching = context => { return true; }, Name="default limit rule", LimitNumber=30, StatWindow=TimeSpan.FromSeconds(1) } }) ));...
}