ASP.NET Core使用固定窗口限流
算法原理
固定窗口算法又称计数器算法,是一种简单的限流算法。在单位时间内设定一个阈值和一个计数值,每收到一个请求则计数值加一,如果计数值超过阈值则触发限流,如果达不到则请求正常处理,进入下一个单位时间后,计数值清零,重新累计。
如上图所示,时间单位是1秒,阈值是3。
- 第1秒3个请求,不会触发限流;
- 第2秒1个请求,不会触发限流;
- 第3秒4个请求,这一秒的前3个请求正常处理,第4个请求触发限流,会被拒绝处理。
- 后续第4秒、第5秒不会触发限流,所有请求正常处理。
算法实现
这里讲两种实现方法:进程内即内存固定窗口算法、基于redis的固定窗口算法。
进程内即内存固定窗口算法
使用字典,key是限流目标,value包括计数值和过期时间。处理请求时,首先从请求中提取限流目标,然后根据限流目标去字典中查找,如果不存在,则添加一个字典项,计数值是1,过期时间是当前时间+限流单位时间;如果存在,则检查是否过期,如果过期,则计数值归1,过期时间是当前时间+限流单位时间,如果未过期,则仅计数值加1。这里需要注意多线程问题,读写数据时需要加锁。
在c#语言中可以使用memorycache,它的缓存项有一个过期时间,不需要自己回收过期的项目。
进程内计数的方法最适合单实例处理的程序限流,多实例处理的情况下可能每个实例收到的请求数不均匀,不能保证限流效果。
基于redis的固定窗口算法
redis作为kv存储,类似于字典,而且也自带过期时间。处理请求时,首先从请求中提取限流目标,然后根据限流目标去redis中查找,如果不存在,则添加kv项,value值是1,过期时间是当前时间+限流单位时间;如果存在,则value值加1。
这些操作逻辑可以封装在一个lua script中,因为lua script在redis中执行时也是原子操作,所以redis的限流计数在分布式处理时天然就是准确的。
算法应用
这里以限流组件 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 inprocessfixedwindowalgorithm( new[] { new fixedwindowrule() { extracttarget = context => { // 提取限流目标 return (context as httpcontext).request.path.value; }, checkrulematching = context => { // 判断当前请求是否需要限流处理 return true; }, name="fixed window limit rule", limitnumber=30, // 限流阈值 statwindow=timespan.fromseconds(1) // 限流单位时间 } }) ); ... } public void configure(iapplicationbuilder app, iwebhostenvironment env) { ... app.useratelimit(); ... }
如上需要先注册服务,然后使用中间件。
注册服务的时候需要提供限流算法和对应的规则:
- 这里使用进程内固定窗口算法inprocessfixedwindowalgorithm,还可以使用redisfixedwindowalgorithm,需要传入一个redis连接。
- 限流阈值是30,限流单位时间是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#aspnet
fireflysoft.ratelimit 是一个基于 .net standard 的限流类库,其内核简单轻巧,能够灵活应对各种需求的限流场景。
其主要特点包括:
- 多种限流算法:内置固定窗口、滑动窗口、漏桶、令牌桶四种算法,还可自定义扩展。
- 多种计数存储:目前支持内存、redis两种存储方式。
- 分布式友好:通过redis存储支持分布式程序统一计数。
- 限流目标灵活:可以从请求中提取各种数据用于设置限流目标。
- 支持限流惩罚:可以在客户端触发限流后锁定一段时间不允许其访问。
- 动态更改规则:支持程序运行时动态更改限流规则。
- 自定义错误:可以自定义触发限流后的错误码和错误消息。
- 普适性:原则上可以满足任何需要限流的场景。
github开源地址:https://github.com/bosima/fireflysoft.ratelimit
到此这篇关于asp.net core使用固定窗口限流的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: HTML拾遗
推荐阅读
-
ASP.NET Core静态文件的使用方法
-
ASP.Net Core中使用枚举类而不是枚举的方法
-
Asp.net Core中如何使用中间件来管理websocket
-
ASP.NET Core Kestrel 中使用 HTTPS (SSL)
-
ASP.NET Core部署前期准备 使用Hyper-V安装Ubuntu Server 16.10
-
使用 xUnit 编写 ASP.NET Core WebAPI单元测试
-
Asp.net core WebApi 使用Swagger生成帮助页实例
-
ASP.NET core Web中使用appsettings.json配置文件的方法
-
详解在ASP.NET Core 中使用Cookie中间件
-
Asp.Net Core WebAPI使用Swagger时API隐藏和分组详解