ASP.NET Core對(duì)不同類型的用戶進(jìn)行區(qū)別限流詳解
前言
老板提出了一個(gè)新需求,從某某天起,免費(fèi)用戶每天只能查詢100次,收費(fèi)用戶100W次。
這是一個(gè)限流問題,聰明的你也一定想到了如何去做:記錄用戶每一天的查詢次數(shù),然后根據(jù)當(dāng)前用戶的類型使用不同的數(shù)字做比較,超過指定的數(shù)字就返回錯(cuò)誤。
嗯,原理就是這么簡(jiǎn)單。不過真正寫起來還要考慮更多問題:
- 統(tǒng)計(jì)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)是什么樣的?字典 or 行記錄?
- 統(tǒng)計(jì)數(shù)據(jù)記錄到哪里??jī)?nèi)存 or MySQL or Redis?
- 分布式應(yīng)用怎么精確計(jì)數(shù)?分布式鎖 or 隊(duì)列 or 事務(wù)?
- 吞吐量比較大時(shí)如何扛得????jī)?nèi)存 or Redis or 數(shù)據(jù)庫集群?
- 這些數(shù)據(jù)要一直保留嗎?自動(dòng)過期 or 定期清理?
- 如何返回錯(cuò)誤?自定義錯(cuò)誤 or HTTP標(biāo)準(zhǔn)錯(cuò)誤碼?
自己去做這些事還是有點(diǎn)麻煩的,這里介紹一個(gè)ASP.NET Core的中間件來滿足這個(gè)限流需求:FireflySoft.RateLimit.AspNetCore。使用步驟如下:
1、安裝Nuget包
已經(jīng)發(fā)布到nuget.org,有多種安裝方式,選擇自己喜歡的就行了。
包管理器命令:
Install-Package FireflySoft.RateLimit.AspNetCore
或者.NET命令:
dotnet add package FireflySoft.RateLimit.AspNetCore
或者項(xiàng)目文件直接添加:
<ItemGroup> <PackageReference Include="FireflySoft.RateLimit.AspNetCore" Version="1.2.0" /> </ItemGroup>
2、使用中間件
在Startup.Configure中使用中間件,演示代碼如下(下邊會(huì)有詳細(xì)說明):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseRateLimit(new RateLimitProcessor<HttpContext>.Builder() .WithAlgorithm(new FixedWindowAlgorithm<HttpContext>( new[] { new FixedWindowRateLimitRule<HttpContext>() { Id = "1", ExtractTarget = context => { // 這里假設(shè)用戶Id是從cookie中傳過來的,需根據(jù)實(shí)際情況獲取 return context.Request.GetTypedHeaders().Get<string>("userId"); }, CheckRuleMatching = context => { // 這里假設(shè)用戶類型是從cookie中傳過來的,實(shí)際可能需要根據(jù)用戶Id再去查詢 // 0免費(fèi)用戶 1收費(fèi)用戶 int userType = context.Request.GetTypedHeaders().Get<int>("userType"); if(userType==0){ return true; } return false; }, Name="免費(fèi)用戶限流規(guī)則", LimitNumber=100, StatWindow=TimeSpan.FromDays(1) }, new FixedWindowRateLimitRule<HttpContext>() { Id = "2", ExtractTarget = context => { // 這里假設(shè)用戶Id是從cookie中傳過來的,需根據(jù)實(shí)際情況獲取 return context.Request.GetTypedHeaders().Get<string>("userId"); }, CheckRuleMatching = context => { // 這里假設(shè)用戶類型是從cookie中傳過來的,實(shí)際可能需要根據(jù)用戶Id再去查詢 // 0免費(fèi)用戶 1收費(fèi)用戶 int userType = context.Request.GetTypedHeaders().Get<int>("userType"); if(userType==1){ return true; } return false; }, Name="收費(fèi)用戶限流規(guī)則", LimitNumber=1000000, StatWindow=TimeSpan.FromDays(1) } })) .WithError(new Core.RateLimitError() { Code=429, Message = "查詢數(shù)達(dá)到當(dāng)天最大限制" }) //.WithStorage(new RedisStorage(StackExchange.Redis.ConnectionMultiplexer.Connect("localhost"))) .Build()); ... }
使用此中間件需要構(gòu)建一個(gè)名為RateLimitProcessor的限流處理器實(shí)例,指定限流處理的請(qǐng)求類型HttpContext,設(shè)置限流處理的三個(gè)方面:
限流使用的算法以及對(duì)應(yīng)的規(guī)則
限流算法,根據(jù)這個(gè)需求使用固定窗口算法就可以了,也稱為計(jì)數(shù)器算法。此中間件還提供了滑動(dòng)窗口算法、漏桶算法、令牌桶算法,可以根據(jù)需要選擇。
不同的限流算法有不同的限流規(guī)則類型,在這里使用的是固定窗口限流規(guī)則,針對(duì)免費(fèi)用戶和收費(fèi)用戶分別定義了兩個(gè)規(guī)則,注意其中的幾個(gè)參數(shù):
- Id:在當(dāng)前的版本中Id必須手動(dòng)指定,并且不能重復(fù)。
- ExtractTarget:傳遞一個(gè)方法用于從請(qǐng)求中提取限流目標(biāo),這里就是用戶Id。
- CheckRuleMatching傳遞一個(gè)方法用于檢查當(dāng)前請(qǐng)求是否適用當(dāng)前規(guī)則,這里根據(jù)用戶類型進(jìn)行判斷。
- StatWindow是固定窗口的大小,是一個(gè)時(shí)間跨度,這里是1天。
- LimitNumber是限流值,在StatWindow時(shí)間內(nèi)請(qǐng)求數(shù)超過它就會(huì)觸發(fā)限流。
這里有兩個(gè)比較有意思的設(shè)置:ExtractTarget和CheckRuleMatching,他們共同作用,讓用戶可以完全自由的定制自己限流的目標(biāo)和條件,無論是IP、ClientId或者Url。
限流統(tǒng)計(jì)數(shù)據(jù)的持久化方式
FireflySoft.RateLimit中的限流計(jì)數(shù)目前支持保存在內(nèi)存或者Redis中,也可以通過實(shí)現(xiàn)IRateLimitStorage來定義一個(gè)新的存儲(chǔ)器,不設(shè)置時(shí)默認(rèn)為內(nèi)存存儲(chǔ)。
對(duì)于只需要部署一份的程序,絕大部分情況下使用內(nèi)存就夠了;但是如果限流的時(shí)間窗口比較長,比如1小時(shí)限制300次,重啟就會(huì)丟失計(jì)數(shù),這可能是個(gè)風(fēng)險(xiǎn),此時(shí)使用Redis會(huì)比較合適。對(duì)于分布式應(yīng)用,也建議使用Redis存儲(chǔ)。
限流統(tǒng)計(jì)數(shù)據(jù)會(huì)根據(jù)限流時(shí)間窗口自動(dòng)過期移除。
被限流時(shí)的錯(cuò)誤碼和消息
默認(rèn)限流錯(cuò)誤Code是429,這個(gè)會(huì)作為HttpStatusCode返回;Message默認(rèn)為null,你可以修改為自己的任意文字提示,這個(gè)會(huì)作為Http Body的內(nèi)容返回。
以上就是使用FireflySoft.RateLimit.AspNetCore對(duì)不同類型的用戶進(jìn)行區(qū)別限流的使用方法。
如果覺得還是限制的有點(diǎn)死,比如返回錯(cuò)誤信息部分,想返回一個(gè)json格式的錯(cuò)誤消息,還可以使用FireflySoft.RateLimit.Core這個(gè)包來封裝自己的ASP.NET Core中間件。
如果想在這個(gè)程序的基礎(chǔ)上再改造下,可以fork這個(gè)項(xiàng)目:https://github.com/bosima/FireflySoft.RateLimit
總結(jié)
到此這篇關(guān)于ASP.NET Core對(duì)不同類型的用戶進(jìn)行區(qū)別限流的文章就介紹到這了,更多相關(guān)ASP.NET Core用戶區(qū)別限流內(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中使用漏桶算法限流的問題
- ASP.NET?Core中使用滑動(dòng)窗口限流的問題及場(chǎng)景分析
- ASP.NET?Core使用固定窗口限流
- ASP.NET Core中使用令牌桶限流的實(shí)現(xiàn)
- Asp.NET Core 限流控制(AspNetCoreRateLimit)的實(shí)現(xiàn)
- 在Asp.netCore中使用Attribute來描述限流的操作步驟
相關(guān)文章
asp.net服務(wù)器端指令include的使用及優(yōu)勢(shì)介紹
將指定文件的內(nèi)容插入 ASP.NET 文件中,包括網(wǎng)頁(.aspx 文件)、用戶控件文件(.ascx 文件)和 Global.asax 文件2013-04-04基于asp.net下使用jquery實(shí)現(xiàn)ajax的解決方法
本文以最簡(jiǎn)單的方法為新手示范如何使用jquery實(shí)現(xiàn)ajax技術(shù)(所以本文是專為新手所寫,老鳥勿噴,大神此處省略一萬字)。至于什么是jquery什么是ajax,自己谷歌去2013-05-05.net core下對(duì)于附件上傳下載的實(shí)現(xiàn)示例
本篇文章主要介紹了.net core下對(duì)于附件上傳下載的實(shí)現(xiàn)示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03ASP.NET中為TextBox中添加calendar.js示例代碼
為TextBox中添加calendar.js對(duì)于一些新手朋友確實(shí)有點(diǎn)難度,下面為大家介紹下ASP.NET中具體的實(shí)現(xiàn)方法2013-11-11C#中實(shí)現(xiàn)偽靜態(tài)頁面兩種方式介紹
偽靜態(tài)技術(shù)的誕生,帶動(dòng)了于搜索引擎友好C#中實(shí)現(xiàn)偽靜態(tài)頁面有兩種方式,本文將一一詳解,感興趣的朋友可以參考下,希望本文對(duì)你學(xué)習(xí)偽靜態(tài)有所幫助2013-01-01.NET實(shí)現(xiàn)文件跨服務(wù)器上傳下載的方法
這篇文章主要給大家介紹了.NET文件如何實(shí)現(xiàn)跨服務(wù)器上傳下載的方法,文中通過圖片介紹的很詳細(xì),相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,有需要的朋友們可以跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2016-12-12Entity Framework Core延遲加載(懶加載)用法
這篇文章介紹了Entity Framework Core延遲加載(懶加載)的使用方式,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02MVC+EasyUI+三層新聞網(wǎng)站建立 實(shí)現(xiàn)登錄功能(四)
這篇文章主要為大家詳細(xì)介紹了MVC+EasyUI+三層新聞網(wǎng)站建立的第四篇,教大家實(shí)現(xiàn)登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html
ASP.NET技巧:請(qǐng)求網(wǎng)址并解析返回的html...2006-09-09