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

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

