解決ASP.NET?Core中使用漏桶算法限流的問題
漏桶算法是限流的四大主流算法之一,其應(yīng)用場景各種資料中介紹的不多,一般都是說應(yīng)用在網(wǎng)絡(luò)流量控制中。這里舉兩個例子:
1、目前家庭上網(wǎng)都會限制一個固定的帶寬,比如100M、200M等,一棟樓有很多的用戶,那么運營商怎么保證某些用戶沒有使用過多的帶寬,從而影響到別人呢?這時就可以使用漏桶算法,限制每個用戶訪問網(wǎng)絡(luò)的最大帶寬,當(dāng)然實際會比這復(fù)雜很多。
2、有一個祖?zhèn)鹘涌?,?dāng)時寫的時候沒有任何保護措施,現(xiàn)在訪問量稍微大點就會崩潰,但是代碼誰也改不動。這時候也可以用漏桶算法,把這個接口封裝一下,將外部請求通過漏桶算法進行整流,再轉(zhuǎn)發(fā)給這個接口,此時訪問頻率不會超過閾值,接口就不會崩潰了。
算法原理
說了這么多,那漏桶算法到底是怎么解決問題的呢?請看下圖。

接收到請求后,先把請求放到一個漏桶中,漏桶以恒定的速率漏出請求,然后漏出的請求被處理;如果接收請求的速度過快,導(dǎo)致漏桶滿了,則丟棄新的請求。
可以看出,漏桶算法主要是通過恒速的方式輸出,給后續(xù)數(shù)據(jù)處理一個穩(wěn)定的輸入。這樣它就能應(yīng)對一定的突發(fā)流量,使系統(tǒng)不會因為請求量突增而導(dǎo)致崩潰,只不過是通過增加延遲的方式,會有那么一點浪費資源,這和令牌桶的處理方式不同,關(guān)于令牌桶算法可以看這篇文章:ASP.NET Core中使用令牌桶限流。
還有一個不常提及的好處,恒速的輸出有時候也可以提升效率,比如一次允許漏出兩個請求,則可以將兩次處理合并為一次處理,如果每次處理都涉及到網(wǎng)絡(luò)IO,則合并處理就有機會減少網(wǎng)絡(luò)IO的開銷。
算法實現(xiàn)
這里講兩種實現(xiàn)方法:進程內(nèi)即內(nèi)存漏桶算法、基于Redis的漏桶算法。
進程內(nèi)即內(nèi)存漏桶算法
這里在請求時計算漏出數(shù)量,沒有單獨的漏出處理,描述的算法稍顯復(fù)雜,不過只需要增加一點耐心,也很容易理解。
先來定義幾個變量:
- 對于漏出速率,用 [每X時間周期Y個] 來表示。X時間周期一般是若干秒、分鐘、小時等時間跨度。
- 對于當(dāng)前時間周期的開始時間用Ts表示,當(dāng)前時間周期的結(jié)束時間用Te表示,當(dāng)前時間用Ti表示。
- 對于漏桶容量,用Z來表示。
- 對于X時間內(nèi)的所有請求數(shù)量,用N來表示。
當(dāng)請求到達時,則可以按以下次序處理:
- 如果Ti-Ts<=X,說明還在當(dāng)前時間周期內(nèi),先增加N的值:
比較N和Y,如果N<=Y,則請求無需等待,直接漏出,進入處理階段;
如果N>Y,則比較N與Y+Z:
如果N<=Y+Z,則請求進入漏桶等待,等待時間為:(math.ceiling((N-Y)/Y)-1)*X+(Te - Ti),等待結(jié)束后漏出,進入處理階段;
如果N>Y+Z,則請求無法進入漏桶,只能丟棄掉,實現(xiàn)上就是拒絕請求;
- 如果Ti-Ts>X,則需要創(chuàng)建新的時間周期:
計算過去了幾個時間周期:Pn=math.ceiling((Ti-Te)/X);
- 重設(shè)Ts和Te的值:Ts=上次的Ts+Pn*X,Te=Ts+X;
- 計算這段時間最大可以漏出的數(shù)量:Yo=Pn*Y;
- 計算N的值:N= N-Yo<=0 ? 0: N-Yo;
- 此時符合Ti-Ts<=X,又在當(dāng)前時間周期內(nèi)了,再回到上邊的步驟依次處理。
基于Redis的漏桶算法
基于Redis也可以實現(xiàn)上述的算法,只不過變量的表示方式換成了Redis KV,算法邏輯還是一樣的。
這些操作邏輯可以封裝在一個Lua script中,因為Lua script在Redis中執(zhí)行時也是原子操作,所以Redis的限流計數(shù)在分布式部署時天然就是準(zhǔn)確的。
應(yīng)用算法
雖然業(yè)務(wù)服務(wù)中不怎么常用,這里還是以限流組件 FireflySoft.RateLimit 為例,實現(xiàn)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 InProcessLeakyBucketAlgorithm(
new[] {
// 三個參數(shù):漏桶的容量、單位時間漏出的數(shù)量、漏出的單位時間
new LeakyBucketRule(20,10, TimeSpan.FromSeconds(1))
{
ExtractTarget = context =>
{
// 提取限流目標(biāo)
return (context as HttpContext).Request.Path.Value;
},
CheckRuleMatching = context =>
{
// 判斷當(dāng)前請求是否需要限流處理
return true;
},
Name="leaky bucket limit rule",
}
})
);
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseRateLimit();
...
}
如上需要先注冊服務(wù),然后使用中間件。
注冊服務(wù)的時候需要提供限流算法和對應(yīng)的規(guī)則:
- 這里使用進程內(nèi)漏桶算法InProcessLeakyBucketAlgorithm,還可以使用RedisLeakyBucketAlgorithm,需要傳入一個Redis連接。兩種算法都支持同步和異步方法。
- 漏桶的容量是20,單位時間漏出的數(shù)量10,漏出的單位時間是1秒。也就是說1秒漏出10個,1秒內(nèi)超出10個請求就會被延遲處理,加上漏桶的容量,1秒內(nèi)超出30個請求就會被限流。
- ExtractTarget用于提取限流目標(biāo),這里是每個不同的請求Path,可以根據(jù)需求從當(dāng)前請求中提取關(guān)鍵數(shù)據(jù),然后設(shè)定各種限流目標(biāo)。如果有IO請求,這里還支持對應(yīng)的異步方法ExtractTargetAsync。
- CheckRuleMatching用于驗證當(dāng)前請求是否限流,傳入的對象也是當(dāng)前請求,方便提取關(guān)鍵數(shù)據(jù)進行驗證。如果有IO請求,這里還支持對應(yīng)的異步方法CheckRuleMatchingAsync。
- 默認被限流時會返回HttpStatusCode 429,可以在AddRateLimit時使用可選參數(shù)error自定義這個值,以及Http Header和Body中的內(nèi)容。
基本的使用就是上邊例子中的這些了。
如果還是基于傳統(tǒng)的.NET Framework,則需要在Application_Start中注冊一個消息處理器RateLimitHandler,算法和規(guī)則部分都是共用的,具體可以看Github上的使用說明:https://github.com/bosima/FireflySoft.RateLimit
FireflySoft.RateLimit 是一個基于 .NET Standard 的限流類庫,其內(nèi)核簡單輕巧,能夠靈活應(yīng)對各種需求的限流場景。
其主要特點包括:
- 多種限流算法:內(nèi)置固定窗口、滑動窗口、漏桶、令牌桶四種算法,還可自定義擴展。
- 多種計數(shù)存儲:目前支持內(nèi)存、Redis兩種存儲方式。
- 分布式友好:通過Redis存儲支持分布式程序統(tǒng)一計數(shù)。
- 限流目標(biāo)靈活:可以從請求中提取各種數(shù)據(jù)用于設(shè)置限流目標(biāo)。
- 支持限流懲罰:可以在客戶端觸發(fā)限流后鎖定一段時間不允許其訪問。
- 動態(tài)更改規(guī)則:支持程序運行時動態(tài)更改限流規(guī)則。
- 自定義錯誤:可以自定義觸發(fā)限流后的錯誤碼和錯誤消息。
- 普適性:原則上可以滿足任何需要限流的場景。
Github開源地址:https://github.com/bosima/FireflySoft.RateLimit
到此這篇關(guān)于ASP.NET Core中使用漏桶算法限流的文章就介紹到這了,更多相關(guān)ASP.NET Core限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Asp.Net?Core7?preview4限流中間件新特性詳解
- ASP.NET?Core設(shè)置Ocelot網(wǎng)關(guān)限流
- ASP.NET?Core基于滑動窗口實現(xiàn)限流控制
- ASP.NET?Core中間件實現(xiàn)限流的代碼
- ASP.NET?Core中使用滑動窗口限流的問題及場景分析
- ASP.NET?Core使用固定窗口限流
- ASP.NET Core中使用令牌桶限流的實現(xiàn)
- Asp.NET Core 限流控制(AspNetCoreRateLimit)的實現(xiàn)
- ASP.NET Core對不同類型的用戶進行區(qū)別限流詳解
- 在Asp.netCore中使用Attribute來描述限流的操作步驟
相關(guān)文章
asp.net中ADO SQL數(shù)據(jù)庫 筆記匯總 持續(xù)更新中
asp.net中ADO SQL數(shù)據(jù)庫 筆記匯總 持續(xù)更新中,需要的朋友可以參考下2012-07-07
在FireFox/IE下Response中文文件名亂碼問題解決方案
只是針對沒有空格和IE的情況下使用Response.AppendHeader()如果想在FireFox下輸出沒有編碼的文件,并且IE下輸出的文件名中空格不為+號,就要多一次判斷了,接下來將詳細介紹下感興趣的朋友可以了解下,或許對你有所幫助2013-02-02
ASP.NET Core自定義中間件如何讀取Request.Body與Response.Body的內(nèi)容詳解
這篇文章主要給大家介紹了關(guān)于在ASP.NET Core自定義中間件中如何讀取Request.Body與Response.Body的內(nèi)容,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用ASP.NET Core具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
asp.net 數(shù)據(jù)庫的連接和datatable類
asp.net下數(shù)據(jù)庫的連接與數(shù)據(jù)庫datatable類實現(xiàn)代碼。2009-05-05
.NET Core 3.0 可回收程序集加載上下文的實現(xiàn)
這篇文章主要介紹了.NET Core 3.0 可回收程序集加載上下文的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
asp.net(C#)使用QRCode生成圖片中心加Logo或圖像的二維碼實例
這篇文章主要介紹了asp.net(C#)使用QRCode生成圖片中心加Logo或圖像的二維碼,結(jié)合實例形式詳細分析了asp.net基于QRCode生成二維碼的具體實現(xiàn)技巧,需要的朋友可以參考下2016-06-06
.Net中異步任務(wù)的取消和監(jiān)控的具體實現(xiàn)
本文主要介紹了.Net中異步任務(wù)的取消和監(jiān)控的具體實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09

