溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ASP.NET?Core中使用滑動(dòng)窗口限流的問題舉例分析

發(fā)布時(shí)間:2021-12-10 10:47:47 來源:億速云 閱讀:135 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“ASP.NET Core中使用滑動(dòng)窗口限流的問題舉例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“ASP.NET Core中使用滑動(dòng)窗口限流的問題舉例分析”吧!

滑動(dòng)窗口算法用于應(yīng)對(duì)請(qǐng)求在時(shí)間周期中分布不均勻的情況,能夠更精確的應(yīng)對(duì)流量變化,比較著名的應(yīng)用場(chǎng)景就是TCP協(xié)議的流量控制,不過今天要說的是服務(wù)限流場(chǎng)景中的應(yīng)用。

算法原理

這里假設(shè)業(yè)務(wù)需要每秒鐘限流100次,先來看固定窗口算法的兩個(gè)問題:

漏檢

如下圖所示,單看第1秒和第2秒,其請(qǐng)求次數(shù)都沒有超過100,所以使用固定窗口算法時(shí)不會(huì)觸發(fā)限流。但是第1秒的后500ms的請(qǐng)求數(shù)加上第2秒的前500毫秒的請(qǐng)求數(shù)就超過了100,這時(shí)候可能會(huì)給系統(tǒng)帶來傷害,使用固定窗口算法時(shí)不能檢測(cè)到這種情況。

ASP.NET?Core中使用滑動(dòng)窗口限流的問題舉例分析

太剛

針對(duì)漏檢的問題,你可能會(huì)說,可以把時(shí)間窗口設(shè)置為500ms,把限流閾值設(shè)置為50。那么來看下圖,除了第2個(gè)計(jì)數(shù)周期超過了50,從而觸發(fā)限流,前后幾個(gè)計(jì)數(shù)周期的請(qǐng)求都很正常,甚至都不會(huì)超過閾值的50%,可能第2個(gè)計(jì)數(shù)周期的情況實(shí)在太特殊,1天都不會(huì)出現(xiàn)第2次,如果對(duì)系統(tǒng)不會(huì)造成影響,能不能通融下,做不到!固定窗口算法這時(shí)候就會(huì)顯得太過剛性。

ASP.NET?Core中使用滑動(dòng)窗口限流的問題舉例分析

那么滑動(dòng)窗口如何來解決這兩個(gè)問題呢?還是先來看圖:

ASP.NET?Core中使用滑動(dòng)窗口限流的問題舉例分析

如上圖所示:

  • 滑動(dòng)窗口的時(shí)間跨度是1秒,每個(gè)小計(jì)數(shù)周期的時(shí)間跨度是500ms,此處的滑動(dòng)窗口包含2個(gè)小計(jì)數(shù)周期。

  • 隨著時(shí)間的前進(jìn),滑動(dòng)窗口包含的小計(jì)數(shù)周期會(huì)以500ms為單位向前移動(dòng),但始終是包含2個(gè)小計(jì)數(shù)周期。

  • 判斷是否限流時(shí),需要將當(dāng)前滑動(dòng)窗口包含的2個(gè)小計(jì)數(shù)周期的計(jì)數(shù)值加起來。

  • 相比固定窗口計(jì)數(shù)器算法,滑動(dòng)窗口可以有效減少漏檢,如上圖滑動(dòng)窗口移動(dòng)到了500-1500ms,發(fā)現(xiàn)總數(shù)超過100,則觸發(fā)限流;滑動(dòng)窗口在0-1000ms、1000-2000ms時(shí)都不會(huì)觸發(fā)限流,即使其中某個(gè)小周期的計(jì)數(shù)值超過了閾值的半數(shù),但是總數(shù)沒有超過100,就不會(huì)限流,能夠應(yīng)對(duì)極少出現(xiàn)的突發(fā)流量情況。

從分析還可以看出,滑動(dòng)窗口的小周期劃分的越多,則檢測(cè)越準(zhǔn)確,但用于跟蹤的計(jì)數(shù)也越多,使用的內(nèi)存和計(jì)算量都會(huì)增大。

算法實(shí)現(xiàn)

這里講兩種實(shí)現(xiàn)方法:進(jìn)程內(nèi)即內(nèi)存滑動(dòng)窗口算法、基于Redis的滑動(dòng)窗口算法。

進(jìn)程內(nèi)即內(nèi)存滑動(dòng)窗口算法

這里介紹一種性能比較高的方法,使用數(shù)組實(shí)現(xiàn)滑動(dòng)窗口,這是環(huán)形隊(duì)列的一種特例,如下圖所示:

ASP.NET?Core中使用滑動(dòng)窗口限流的問題舉例分析

  • 假設(shè)滑動(dòng)窗口需要5個(gè)小的計(jì)數(shù)周期,則初始化一個(gè)長(zhǎng)度為5的整形數(shù)組,數(shù)字表示數(shù)組中的第幾個(gè)元素。

  • 我們知道隊(duì)列有頭有尾,從隊(duì)頭取出數(shù)據(jù),向隊(duì)尾插入數(shù)據(jù),帶括號(hào)的數(shù)字表示是隊(duì)列中的第幾個(gè)元素。

  • 滑動(dòng)窗口向前移動(dòng)時(shí),隊(duì)尾向右移動(dòng)1位,同時(shí)隊(duì)頭也向右移動(dòng)1位。

  • 隊(duì)尾和隊(duì)頭向右移動(dòng)都可能會(huì)溢出數(shù)組,此時(shí)讓它們回到數(shù)組的起始位置,即圖中數(shù)組的第1個(gè)位置。

關(guān)于這個(gè)算法的詳細(xì)介紹,可以看這篇文章:如何使用數(shù)組實(shí)現(xiàn)滑動(dòng)窗口

基于Redis的滑動(dòng)窗口算法

基于Redis時(shí)也可以使用類似環(huán)形隊(duì)列的方法,比如定義5個(gè)KV作為數(shù)組的5個(gè)元素。不過我之前實(shí)現(xiàn)時(shí)采用了一種更直觀的方式,每個(gè)小的計(jì)數(shù)周期都創(chuàng)建一個(gè)KV,同時(shí)設(shè)置一個(gè)絕對(duì)超過滑動(dòng)窗口時(shí)間跨度的過期時(shí)間,用不到的小計(jì)數(shù)周期不會(huì)一直占用內(nèi)存;判斷是否觸發(fā)限流時(shí),把這些小滑動(dòng)窗口的計(jì)數(shù)值累加起來就可以了。當(dāng)然實(shí)際實(shí)現(xiàn)時(shí)還需要完善一些細(xì)節(jié)上的處理,比如怎么找到這些小計(jì)數(shù)周期,會(huì)有多種方案,存起來或者臨時(shí)計(jì)算都可以。

這些操作邏輯可以封裝在一個(gè)Lua script中,因?yàn)長(zhǎng)ua script在Redis中執(zhí)行時(shí)也是原子操作,所以Redis的限流計(jì)數(shù)在分布式部署時(shí)天然就是準(zhǔn)確的。

應(yīng)用算法

這里以限流組件 FireflySoft.RateLimit 為例,實(shí)現(xiàn)ASP.NET Core中的滑動(dòng)窗口限流。

1、安裝Nuget包

有多種安裝方式,選擇自己喜歡的就行了。

包管理器命令:

Install-Package FireflySoft.RateLimit.AspNetCore

或者.NET命令:

dotnet add package FireflySoft.RateLimit.AspNetCore

或者項(xiàng)目文件直接添加:

<ItemGroup>
<PackageReference Include="FireflySoft.RateLimit.AspNetCore" Version="2.*" />
</ItemGroup>

2、使用中間件

在Startup中使用中間件,演示代碼如下(下邊會(huì)有詳細(xì)說明):

public void ConfigureServices(IServiceCollection services)
        {
           ...
           app.AddRateLimit(new InProcessSlidingWindowAlgorithm(
                new[] {
                		// 構(gòu)造函數(shù)有兩個(gè)參數(shù):滑動(dòng)窗口的時(shí)間長(zhǎng)度、小計(jì)數(shù)周期的時(shí)間長(zhǎng)度
                    new SlidingWindowRule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1))
                    {
                        ExtractTarget = context =>
                        {
                        		// 提取限流目標(biāo)
                            return (context as HttpContext).Request.Path.Value;
                        },
                        CheckRuleMatching = context =>
                        {
                        		// 判斷當(dāng)前請(qǐng)求是否需要限流處理
                            return true;
                        },
                        Name="sliding window limit rule",
                        LimitNumber=100, // 限流閾值,這里即5秒最多100次請(qǐng)求
                    }
                })
            );
            ...
        }

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ...
            app.UseRateLimit();
            ...
        }

如上需要先注冊(cè)服務(wù),然后使用中間件。

注冊(cè)服務(wù)的時(shí)候需要提供限流算法和對(duì)應(yīng)的規(guī)則:

  • 這里使用進(jìn)程內(nèi)固定窗口算法InProcessSlidingWindowAlgorithm,還可以使用RedisSlidingWindowAlgorithm,需要傳入一個(gè)Redis連接。兩種算法都支持同步和異步方法。

  • 限流閾值是100,限流滑動(dòng)窗口是5秒,小計(jì)數(shù)周期是1秒。

  • ExtractTarget用于提取限流目標(biāo),這里是每個(gè)不同的請(qǐng)求Path。如果有IO請(qǐng)求,這里還支持對(duì)應(yīng)的異步方法ExtractTargetAsync。

  • CheckRuleMatching用于驗(yàn)證當(dāng)前請(qǐng)求是否限流。如果有IO請(qǐng)求,這里還支持對(duì)應(yīng)的異步方法CheckRuleMatchingAsync。

  • 默認(rèn)被限流時(shí)會(huì)返回HttpStatusCode 429,可以在AddRateLimit時(shí)使用可選參數(shù)error自定義這個(gè)值,以及Http Header和Body中的內(nèi)容。

基本的使用就是上邊例子中的這些了。

如果還是基于傳統(tǒng)的.NET Framework,則需要在Application_Start中注冊(cè)一個(gè)消息處理器RateLimitHandler,算法和規(guī)則部分都是共用的,具體可以看Github上的使用說明:https://github.com/bosima/FireflySoft.RateLimit

FireflySoft.RateLimit 是一個(gè)基于 .NET Standard 的限流類庫(kù),其內(nèi)核簡(jiǎn)單輕巧,能夠靈活應(yīng)對(duì)各種需求的限流場(chǎng)景。

其主要特點(diǎn)包括:

  • 多種限流算法:內(nèi)置固定窗口、滑動(dòng)窗口、漏桶、令牌桶四種算法,還可自定義擴(kuò)展。

  • 多種計(jì)數(shù)存儲(chǔ):目前支持內(nèi)存、Redis兩種存儲(chǔ)方式。

  • 分布式友好:通過Redis存儲(chǔ)支持分布式程序統(tǒng)一計(jì)數(shù)。

  • 限流目標(biāo)靈活:可以從請(qǐng)求中提取各種數(shù)據(jù)用于設(shè)置限流目標(biāo)。

  • 支持限流懲罰:可以在客戶端觸發(fā)限流后鎖定一段時(shí)間不允許其訪問。

  • 動(dòng)態(tài)更改規(guī)則:支持程序運(yùn)行時(shí)動(dòng)態(tài)更改限流規(guī)則。

  • 自定義錯(cuò)誤:可以自定義觸發(fā)限流后的錯(cuò)誤碼和錯(cuò)誤消息。

  • 普適性:原則上可以滿足任何需要限流的場(chǎng)景。

到此,相信大家對(duì)“ASP.NET Core中使用滑動(dòng)窗口限流的問題舉例分析”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI