限流一般是为了解决因拥挤导致服务无法正常提供的问题。比如常见的地铁限流,如果很多人在很短的时间内快速涌入,超出站台内的空间或列车的可运载人数,就会容易引发安全事故。
在github上使用C#编写的限流程序有很多,翻看了一些,大部分都有很多的场景限制,比如只能用在asp.net core,或者只能使用IP或者ClientId限制,或者对分布式部署不友好,又或者支持的限流算法比较单一。
FireflySoft.RateLimit的目的是提供一个更为基础的限流组件,可以用于各种限流业务场景,可以用于多种形式的程序,可以容纳多种限流算法,支持分布式统一限流,支持灵活的限流目标控制,提供方便的自定义机制,包括各种配置、算法和数据持久化等,同时使用起来更为简便。
下面先简单介绍其使用方法,然后再看一下其逻辑原理。
使用方法
以一个简单的ASP.NET Core WebAPI固定窗口限流为例,要求每个接口每秒钟限制50次请求。使用FireflySoft.RateLimit只需两步:安装Nuget包、使用限流中间件。
1、安装Nuget包
通过包管理器安装:
Install-Package FireflySoft.RateLimit.AspNetCore -Version 1.0.0
或者通过.NET CLI:
dotnet add package FireflySoft.RateLimit.AspNetCore --version 1.0.0
当然你也可以自己编译代码,添加本地引用,开源项目地址:https://github.com/bosima/FireflySoft.RateLimit
2、使用限流中间件
打开 Startup.cs,在Configure方法中添加 app.UseRateLimit,并提供限流的相关设置,包括:限流的请求类型、限流使用的算法、限流的规则、限流计数的持久化方式、限流时的错误消息等等。示例代码如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRateLimit(new Core.RateLimitProcessor<HttpContext>.Builder()
// .WithError(new Core.RateLimitError()
// {
// Code=429,
// Message = "The system is busy, please try again later"
// })
// .WithStorage(new RedisStorage(StackExchange.Redis.ConnectionMultiplexer.Connect("localhost")))
.WithAlgorithm(new FixedWindowAlgorithm<HttpContext>( new[] {
new FixedWindowRateLimitRule<HttpContext>()
{
ExtractTarget = context =>
{
// for all path, you can customize it
return "rule1-" + context.Request.Path.Value;
},
CheckRuleMatching = context =>
{
// limit every request, you can customize it
return true;
},
Name="general limit rule",
LimitNumber=30,
LockSeconds=1,
StatWindow=TimeSpan.FromSeconds(1)
}
}))
.Build());
...
}
复制上边的代码到你的项目中,打开Postman,发起一个Runner,马上就可以体验到FireflySoft.RateLimit的限流效果。
FireflySoft.RateLimit还提供了另外两个Nuget包:
- FireflySoft.RateLimit.AspNet用于基于.NET Framework的ASP.NET项目限流,.NET版本必须是4.6.1及以上。
- FireflySoft.RateLimit.Core是FireflySoft.RateLimit.的核心类库,可以集成到任何类型的项目中进行限流处理。不仅仅是Web服务限流,各种需要数量限制的业务处理都可以使用。
逻辑原理
1、限流处理器
使用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上还提供了演示程序。
2、被限流请求类型
被限流请求类型就是需要被限制的业务请求的类型,在ASP.NET中他可能是HttpRequestMessage,在ASP.NET Core中它可能是HttpContext,在其它业务中它可能是你自定义的一个类型XXXRequest。
被限流请求类型很重要,因为不同的业务可能使用不同的请求类型,而限流处理程序需要从当前请求中提取或关联到限流目标,明确请求类型才能确定提取方法,否则对请求进行限制将无所适从。
3、限流算法和规则
FireflySoft.RateLimit提供了四种常见的限流算法:固定窗口、滑动窗口、漏桶、令牌桶。固定窗口相对最简单,无论是算法的时间复杂度还是分布式环境实现难度都比较有优势,如果需求是在较短的时间内进行限制,比如每秒限制多少次,使用这种算法是最合适的。但是实际场景中请求在时间分布中可能不太均匀,时多时少,根据需求的不同,可能需要选择其它三种限流算法,这里不做说明了,网上已经有很多的场景选择说明。
初始化限流算法还需要提供对应的限流规则,因为不同的算法往往需要不同的参数,这里很难对不同的算法提供完全统一的限流规则,不过这些规则确实是有共同设置项的,比如限流锁定时间、目标提取方法、是否应用限流处理的判断方法等。
以上文【使用方法】中的限流代码为例,做一些介绍:
- FixedWindowAlgorithm是此限流组件提供的固定窗口限流算法。
- FixedWindowRateLimitRule是此限流组件提供的固定窗口限流规则类型;
- HttpContext是业务中需要限制的请求类型,这里是Http请求上下文类型;
- StatWindow是固定窗口的大小,是一个时间跨度;
- LimitNumber是限流值,在StatWindow时间内请求数超过它就会触发限流;
- LockSeconds是触发限流后的锁定时间,此时间内请求都会被阻止,不需要锁定时可以不设置;
- ExtractTarget传递一个方法用于从请求中提取限流目标,这里是用户的每一个请求路径;
- CheckRuleMatching传递一个方法用于检查当前请求是否需要限流检查,这里return true代表所有请求都要经过限流检查。
这里有两个比较有意思的设置:ExtractTarget和CheckRuleMatching,他们共同作用,让用户可以完全自由的定制自己限流的目标和条件,不固定是IP、ClientId或者Url。其它算法规则中每个设置项的含义可以通过其注释了解到。
如果这几个算法还不能满足要求,可以通过实现IRateLimitAlgorithm来定义一个新的算法。
4、计数持久化方式
FireflySoft.RateLimit中的限流计数目前支持保存在内存或者Redis中,也可以通过实现IRateLimitStorage来定义一个新的存储器。
对于只需要部署一份的程序,绝大部分情况下使用内存就够了;但是如果限流的时间窗口比较长,比如1小时限制300次,重启就会丢失计数,这可能是个风险,此时使用Redis会比较合适。
对于需要部署多份的程序,如果请求是基本均匀的,并且在每个部署之间的分配也是均匀的,那么使用内存存储器也未尝不可,将总的限流数平均分配在每一个部署中,只要有一个部署触发限流,其它部署很大几率上也会触发限流。但是对于需要部署多份的情况,采用更持久的Redis方式才是稳妥的。
相比内存访问,Redis访问需要网络交互,这会造成一定的性能损失,访问量很大时也会产生拥堵,不过也可以将请求分散到多个Redis的方式进行缓解;同时分布式环境下数据一致性的实现难度更大,即使使用Redis,比如限流处理中必然会涉及的各种时间,不同节点之间的时间不可能绝对一致,越短的时间窗口协调难度越大。因此使用滑动窗口、漏桶、令牌桶等分布式实现难度较大的算法时,需要注意时间单位的设置。
5、限流错误信息
限流错误信息是触发限流时限流检查结果中附带的信息,目前每个限流处理器允许设置一个统一的RateLimitError,方便业务侧进行统一处理。默认限流错误Code是429,Message为null。你也可以不使用这个定义的值,根据当前限流目标和限流规则构造自己的错误信息。
6、限流锁定
限流锁定是触发限流时的惩罚性处理。FireflySoft.RateLimit通过设置限流规则中的LockSeconds,定义触发限流后的锁定时间,此时间内的请求都会被认定触发限流规则,而不被允许通过;如果不需要锁定忽略这个设置就可以了。
了解源码
FireflySoft.RateLimit已经在Github开源:https://github.com/bosima/FireflySoft.RateLimit
项目 | 说明 |
---|---|
FireflySoft.RateLmit.Core | FireflySoft.RateLmit的算法、规则、持久化和其它核心代码。 |
FireflySoft.RateLmit.Core.Sample | 使用FireflySoft.RateLmit.Core的示例程序。 |
FireflySoft.RateLimit.AspNet | 为基于 .NET Framework的ASP.NET提供的限流组件。 |
FireflySoft.RateLimit.AspNet.Sample | 使用FireflySoft.RateLimit.AspNet的示例程序。 |
FireflySoft.RateLimit.AspNetCore | ASP.NET Core限流中间件。 |
FireflySoft.RateLimit.AspNetCore.Sample | 使用FireflySoft.RateLimit.AspNetCore的示例程序。 |
关键字: 限流
发表评论
相关文章
国内AI资源汇总,AI聊天、AI绘画、AI写作、AI视频、AI设计、AI编程、AI音乐等,国内顺畅访问,无需科学上网。
扫码或点击进入:萤火AI大全
文章分类
最新评论