zoukankan      html  css  js  c++  java
  • ASP.NET Core中使用固定窗口限流请求

    算法原理

    固定窗口算法又称计数器算法,是一种简单的限流算法。在单位时间内设定一个阈值和一个计数值,每收到一个请求则计数值加一,如果计数值超过阈值则触发限流,如果达不到则请求正常处理,进入下一个单位时间后,计数值清零,重新累计。

    WX20211208-222755@2x

    如上图所示,时间单位是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

    收获更多架构知识,请关注公众号 萤火架构。原创内容,转载请注明出处。

    出处:https://www.cnblogs.com/bossma/p/using-fixed-window-rate-limiting-in-asp-net-core.html

    您的资助是我最大的动力!
    金额随意,欢迎来赏!
    款后有任何问题请给我留言。

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的推荐按钮。
    如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我。(●'◡'●)

    如果对你有所帮助,赞助一杯咖啡!打             付款后有任何问题请给我留言!!!

    因为,我的写作热情也离不开您的肯定与支持,感谢您的阅读,我是【Jack_孟】!

  • 相关阅读:
    C#在窗口中ComboBox控件中加载数据库数据
    C#登录窗口(访问数据库)的制作,类文件的制作及使用
    C#通过窗体应用程序操作数据库(增删改查)
    C#在listview控件中显示数据库数据
    C#窗体与sql数据库的连接
    C#记事本的制作
    C#计算器的制作
    C#委托的初步理解
    使用Java语言开发微信公众平台(七)——音乐消息的回复
    使用Java语言开发微信公众平台(六)——获取access_token
  • 原文地址:https://www.cnblogs.com/mq0036/p/15666046.html
Copyright © 2011-2022 走看看