Asp.Net Core 7 preview 4 重磅新特性--限流

前言

限流是應對流量暴增或某些用戶惡意攻擊等場景的重要手段之一,然而微軟官方從未支持這一重要特性,AspNetCoreRateLimit這一第三方庫限流庫一般作為首選使用,然而其配置參數過于繁多,對使用者造成較大的學習成本。令人高興的是,在剛剛發布的.NET 7 Preview 4中開始支持限流中間件。

UseRateLimiter嘗鮮

  1. 安裝.NET 7.0 SDK(v7.0.100-preview.4)

  2. 通過nuget包安裝Microsoft.AspNetCore.RateLimiting

  3. 創建.Net7網站應用,注冊中間件

全局限流并發1個

app.UseRateLimiter(new?RateLimiterOptions
{Limiter?=?PartitionedRateLimiter.Create<HttpContext,?string>(resource?=>{return?RateLimitPartition.CreateConcurrencyLimiter("MyLimiter",_?=>?new?ConcurrencyLimiterOptions(1,?QueueProcessingOrder.NewestFirst,?1));})
});

根據不同資源不同限制并發數/api前綴的資源租約數2,等待隊列長度為2,其他默認租約數1,隊列長度1。

app.UseRateLimiter(new?RateLimiterOptions()
{//?觸發限流的響應碼DefaultRejectionStatusCode?=?500,OnRejected?=?async?(ctx,?rateLimitLease)?=>{//?觸發限流回調處理},Limiter?=?PartitionedRateLimiter.Create<HttpContext,?string>(resource?=>{if?(resource.Request.Path.StartsWithSegments("/api")){return?RateLimitPartition.CreateConcurrencyLimiter("WebApiLimiter",_?=>?new?ConcurrencyLimiterOptions(2,?QueueProcessingOrder.NewestFirst,?2));}else{return?RateLimitPartition.CreateConcurrencyLimiter("DefaultLimiter",_?=>?new?ConcurrencyLimiterOptions(1,?QueueProcessingOrder.NewestFirst,?1));}})
});

本地測試

  1. 新建一個webapi項目,并注冊限流中間件如下

using?Microsoft.AspNetCore.RateLimiting;
using?System.Threading.RateLimiting;var?builder?=?WebApplication.CreateBuilder(args);//?Add?services?to?the?container.builder.Services.AddControllers();
//?Learn?more?about?configuring?Swagger/OpenAPI?at?https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();var?app?=?builder.Build();//?Configure?the?HTTP?request?pipeline.
if?(app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseRateLimiter(new?RateLimiterOptions
{DefaultRejectionStatusCode?=?500,OnRejected?=?async?(ctx,?lease)?=>{await?Task.FromResult(ctx.Response.WriteAsync("ConcurrencyLimiter"));},Limiter?=?PartitionedRateLimiter.Create<HttpContext,?string>(resource?=>{return?RateLimitPartition.CreateConcurrencyLimiter("MyLimiter",_?=>?new?ConcurrencyLimiterOptions(1,?QueueProcessingOrder.NewestFirst,?1));})
});app.UseHttpsRedirection();app.UseAuthorization();app.MapControllers();app.Run();
  1. 啟動項目,使用jmeter測試100并發,請求接口/WeatherForecast2ecd09acbd388bed8a37c48ff759ec07.png所有請求處理成功,失敗0!

這個結果是不是有點失望,其實RateLimitPartition.CreateConcurrencyLimiter創建的限流器是ConcurrencyLimiter,后續可以實現各種策略的限流器進行替換之。看了ConcurrencyLimiter的實現,其實就是令牌桶的限流思想,上面配置的new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 1)),第一個1代表令牌的個數,第二個1代表可以當桶里的令牌為空時,進入等待隊列,而不是直接失敗,當前面的請求結束后,會歸還令牌,此時等待的請求就可以拿到令牌了,QueueProcessingOrder.NewestFirst代表最新的請求優先獲取令牌,也就是獲取令牌時非公平的,還有另一個枚舉值QueueProcessingOrder.OldestFirst老的優先,獲取令牌是公平的。只要我們獲取到令牌的人干活速度快,雖然我們令牌只有1,并發就很高。3. 測試觸發失敗場景 只需要讓我們拿到令牌的人持有時間長點,就能輕易的觸發。bb2be3c0ad9a7d1cfca442f1cb740751.png調整jmater并發數為1005ecfb63bb3efce61ef1c3fc09ed6ede.png

相應內容也是我們設置的內容。56e2534f62a3f5d475fae3891612a4a4.png

ConcurrencyLimiter源碼

令牌桶限流思想

獲取令牌

protected?override?RateLimitLease?AcquireCore(int?permitCount){//?These?amounts?of?resources?can?never?be?acquiredif?(permitCount?>?_options.PermitLimit){throw?new?ArgumentOutOfRangeException(nameof(permitCount),?permitCount,?SR.Format(SR.PermitLimitExceeded,?permitCount,?_options.PermitLimit));}ThrowIfDisposed();//?Return?SuccessfulLease?or?FailedLease?to?indicate?limiter?stateif?(permitCount?==?0){return?_permitCount?>?0???SuccessfulLease?:?FailedLease;}//?Perf:?Check?SemaphoreSlim?implementation?instead?of?lockingif?(_permitCount?>=?permitCount){lock?(Lock){if?(TryLeaseUnsynchronized(permitCount,?out?RateLimitLease??lease)){return?lease;}}}return?FailedLease;}

嘗試獲取令牌核心邏輯

private?bool?TryLeaseUnsynchronized(int?permitCount,?[NotNullWhen(true)]?out?RateLimitLease??lease){ThrowIfDisposed();//?if?permitCount?is?0?we?want?to?queue?it?if?there?are?no?available?permitsif?(_permitCount?>=?permitCount?&&?_permitCount?!=?0){if?(permitCount?==?0){//?Edge?case?where?the?check?before?the?lock?showed?0?available?permits?but?when?we?got?the?lock?some?permits?were?now?availablelease?=?SuccessfulLease;return?true;}//?a.?if?there?are?no?items?queued?we?can?lease//?b.?if?there?are?items?queued?but?the?processing?order?is?newest?first,?then?we?can?lease?the?incoming?request?since?it?is?the?newestif?(_queueCount?==?0?||?(_queueCount?>?0?&&?_options.QueueProcessingOrder?==?QueueProcessingOrder.NewestFirst)){_idleSince?=?null;_permitCount?-=?permitCount;Debug.Assert(_permitCount?>=?0);lease?=?new?ConcurrencyLease(true,?this,?permitCount);return?true;}}lease?=?null;return?false;}

令牌獲取失敗后進入等待隊列

protected?override?ValueTask<RateLimitLease>?WaitAsyncCore(int?permitCount,?CancellationToken?cancellationToken?=?default){//?These?amounts?of?resources?can?never?be?acquiredif?(permitCount?>?_options.PermitLimit){throw?new?ArgumentOutOfRangeException(nameof(permitCount),?permitCount,?SR.Format(SR.PermitLimitExceeded,?permitCount,?_options.PermitLimit));}//?Return?SuccessfulLease?if?requestedCount?is?0?and?resources?are?availableif?(permitCount?==?0?&&?_permitCount?>?0?&&?!_disposed){return?new?ValueTask<RateLimitLease>(SuccessfulLease);}//?Perf:?Check?SemaphoreSlim?implementation?instead?of?lockinglock?(Lock){if?(TryLeaseUnsynchronized(permitCount,?out?RateLimitLease??lease)){return?new?ValueTask<RateLimitLease>(lease);}//?Avoid?integer?overflow?by?using?subtraction?instead?of?additionDebug.Assert(_options.QueueLimit?>=?_queueCount);if?(_options.QueueLimit?-?_queueCount?<?permitCount){if?(_options.QueueProcessingOrder?==?QueueProcessingOrder.NewestFirst?&&?permitCount?<=?_options.QueueLimit){//?remove?oldest?items?from?queue?until?there?is?space?for?the?newest?requestdo{RequestRegistration?oldestRequest?=?_queue.DequeueHead();_queueCount?-=?oldestRequest.Count;Debug.Assert(_queueCount?>=?0);if?(!oldestRequest.Tcs.TrySetResult(FailedLease)){//?Updating?queue?count?is?handled?by?the?cancellation?code_queueCount?+=?oldestRequest.Count;}}while?(_options.QueueLimit?-?_queueCount?<?permitCount);}else{//?Don't?queue?if?queue?limit?reached?and?QueueProcessingOrder?is?OldestFirstreturn?new?ValueTask<RateLimitLease>(QueueLimitLease);}}CancelQueueState?tcs?=?new?CancelQueueState(permitCount,?this,?cancellationToken);CancellationTokenRegistration?ctr?=?default;if?(cancellationToken.CanBeCanceled){ctr?=?cancellationToken.Register(static?obj?=>{((CancelQueueState)obj!).TrySetCanceled();},?tcs);}RequestRegistration?request?=?new?RequestRegistration(permitCount,?tcs,?ctr);_queue.EnqueueTail(request);_queueCount?+=?permitCount;Debug.Assert(_queueCount?<=?_options.QueueLimit);return?new?ValueTask<RateLimitLease>(request.Tcs.Task);}}

歸還令牌

private?void?Release(int?releaseCount){lock?(Lock){if?(_disposed){return;}_permitCount?+=?releaseCount;Debug.Assert(_permitCount?<=?_options.PermitLimit);while?(_queue.Count?>?0){RequestRegistration?nextPendingRequest?=_options.QueueProcessingOrder?==?QueueProcessingOrder.OldestFirst??_queue.PeekHead():?_queue.PeekTail();if?(_permitCount?>=?nextPendingRequest.Count){nextPendingRequest?=_options.QueueProcessingOrder?==?QueueProcessingOrder.OldestFirst??_queue.DequeueHead():?_queue.DequeueTail();_permitCount?-=?nextPendingRequest.Count;_queueCount?-=?nextPendingRequest.Count;Debug.Assert(_permitCount?>=?0);ConcurrencyLease?lease?=?nextPendingRequest.Count?==?0???SuccessfulLease?:?new?ConcurrencyLease(true,?this,?nextPendingRequest.Count);//?Check?if?request?was?canceledif?(!nextPendingRequest.Tcs.TrySetResult(lease)){//?Queued?item?was?canceled?so?add?count?back_permitCount?+=?nextPendingRequest.Count;//?Updating?queue?count?is?handled?by?the?cancellation?code_queueCount?+=?nextPendingRequest.Count;}nextPendingRequest.CancellationTokenRegistration.Dispose();Debug.Assert(_queueCount?>=?0);}else{break;}}if?(_permitCount?==?_options.PermitLimit){Debug.Assert(_idleSince?is?null);Debug.Assert(_queueCount?==?0);_idleSince?=?Stopwatch.GetTimestamp();}}}

總結

雖然這次官方對限流進行了支持,但貌似還不能支持對ip或client級別的限制支持,對于更高級的限流策略仍需要借助第三方庫或自己實現,期待后續越來越完善。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287607.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287607.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287607.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【計算機圖形學】實驗:C#.net環境下采用GDI+圖形特技處理案例教程

一、實驗目的 掌握在.net環境下對圖形特技的處理方法。 二、實驗準備 學習在.net環境下讀取圖像文件、改變顏色等基本知識。 三、實驗內容 在.net環境中實現對圖像的灰度化處理、柔化和銳化、底片濾鏡、淡入淡出以及浮雕、油畫和木刻等藝術效果。 四、實驗過程及步驟 (…

Windows之在終端打開當前目錄的命令

1 問題 Windows在終端打開當前目錄的命令 2 命令如下 1)、通過start命令 start . 2)、通過explorer命令 explorer .3 linux終端打開當前目錄命令如下 nautilus . 4 mac終端打開當前目錄命令如下 open .

孫鐘秀-《 操作系統教程 》(第4版)注釋(稿)

http://www.valleytalk.org/2014/12/30/%E5%AD%99%E9%92%9F%E7%A7%80-%E3%80%82%E3%80%8A-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%95%99%E7%A8%8B-%E3%80%8B%EF%BC%88%E7%AC%AC4%E7%89%88%EF%BC%89%E6%B3%A8%E9%87%8A%EF%BC%88%E7%A8%BF/轉載于:https://www.cnblogs.com/zen…

Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念區分

如果開發的應用用戶較多&#xff0c;那么必須保證應用在多個版本不同的設備上能夠正確的運行。這就要求對各個版本比較熟悉&#xff0c;知道在什么版本中加入了什么新的功能或特性。但是Android的版本太多了&#xff0c;是個令人頭疼的問題。如果想了解Android的版本差異&#…

mysql交叉編譯 cmake_CMake交叉編譯配置

很多時候&#xff0c;我們在開發的時候是面對嵌入式平臺&#xff0c;因此由于資源的限制需要用到相關的交叉編譯。即在你host宿主機上要生成target目標機的程序。里面牽扯到相關頭文件的切換和編譯器的選擇以及環境變量的改變等&#xff0c;我今天僅僅簡單介紹下相關CMake在面對…

[python opencv 計算機視覺零基礎到實戰] 一 opencv的helloworld

前置條件 說明&#xff1a;本系列opencv實戰教程將從基礎到實戰&#xff0c;若只是簡單學習完python也可以通過該教程完成一般的機器學習編程&#xff1b;文中將會對很多python的基礎內容進行講解&#xff0c;但由于文章定位的原因將不會贅述過多的基礎內容&#xff0c;基礎內…

Android之用setColorFilter在ImageView上面覆蓋一層灰色的圖層

1 問題 在圖片上面覆蓋一層灰色的圖層 2 解決辦法 比如點擊圖片覆蓋黑色 imageView.setColorFilter(ContextCompat.getColor(context, R.color.picture_color_black_80), PorterDuff.Mode.SRC_ATOP); 然后點擊圖片還原回來 imageView.setColorFilter(ContextCompat.getCol…

【計算機圖形學】實驗:VB.net環境下的綜合繪圖與交互技術案例教程

一、實驗目的 掌握在.net環境下的繪圖軟件界面設計與交互技術。 二、實驗準備 學習在.net環境下的界面設計的一般原理與交互技術等基本知識。 三、實驗內容 將前7個實驗內容集成到一個界面下&#xff0c;如直線段、圓、矩形與曲線的繪制填充&#xff0c;以及對圖像的處理&…

IE8 兼容background-size的解決辦法

.bgpic { background-image:url(); background-size:cover; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src,sizingMethodscale); } 注意progid里面的src路徑是絕對路徑或是相對于頁面的路徑。? div class"bgpic"style"width:200px;height:1…

從頭開始敲代碼之《從BaseApplication/Activity開始》

轉載請注明出處王亟亟的大牛之路 其安易持&#xff0c;其未兆易謀&#xff1b;其脆易泮&#xff0c;其微易散。為之于未有&#xff0c;治之于未亂。合抱之木&#xff0c;生于毫末&#xff1b;九層之臺&#xff0c;起于壘土&#xff1b;千里之行&#xff0c;始于足下。為者敗之…

查缺補漏系統學習 EF Core 6 - 原始 SQL 查詢

推薦關注「碼俠江湖」加星標&#xff0c;時刻不忘江湖事這是 EF Core 系列的第五篇文章&#xff0c;上一篇文章盤點了 EF Core 中的幾種數據查詢方式。但是有有時候&#xff0c;我們可能無法用標準的 LINQ 方法完成查詢任務。或者編譯后的 LINQ 查詢&#xff0c;沒有我們想要的…

【python opencv 計算機視覺零基礎到實戰】二、 opencv文件格式與攝像頭讀取

一、學習目標 了解圖片的結構屬性了解如何捕獲視頻了解waitkey的使用方法 目錄 [python opencv 計算機視覺零基礎到實戰] 一、opencv的helloworld [【python opencv 計算機視覺零基礎到實戰】二、 opencv文件格式與攝像頭讀取] 一、opencv的helloworld [[python opencv 計…

python冒泡排序代碼完整_用Python寫冒泡排序代碼

python代碼實現冒泡排序代碼其實很簡單&#xff0c;具體代碼如下所示&#xff1a;代碼Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 def bubbleSort(numbers):for j in xrange(len(numbers),-1,-1):for i in xra…

[C++]VS2005(VC8) 使用 Boost

測試環境&#xff1a;[1] Widnows XP Professional[2] Visual Studio 2005 Team Studio(VC8.0)[3] WinCvs 1.31. 下載 Boost透過 CVS 下載最新版 cvs -d:pserver:anonymousboost.cvs.sourceforge.net:/cvsroot/boost login [詢問密碼時&#xff0c;直接輸入 Enter 略過] cvs …

Android之編譯提示error: Apostrophe not preceded by

1 問題 as編譯提示錯誤如下 error: Apostrophe not preceded by 2 原因 字符串資源文件里面value包含一個單引號 <string name"key">Don t ....</string> 2 解決辦法 1) 加雙引號 <string name"key">"Don t ...."</s…

【ArcObject開發】實驗:ArcGIS Desktop開發方式入門基礎教程

一、實驗目的: 熟練掌握ArcGIS Desktop開發方式。 二、實驗準備: 學習ArcGIS Desktop定制步驟;熟悉VBA編程環境、Active DLL和Active EXE開發一般過程。 三、實驗內容: (1)描述在ArcGIS Desktop環境下定制窗體界面的一般步驟;(2)在VBA環境下編寫宏,實現圖層視圖…

C# WPF后臺動態添加控件(經典)

概述在Winform中從后臺添加控件相對比較容易&#xff0c;但是在WPF中&#xff0c;我們知道界面是通過XAML編寫的&#xff0c;如何把后臺寫好的控件動態添加到前臺呢&#xff1f;本節舉例介紹這個問題。這里要用到UniformGrid布局&#xff0c;UniformGrid 是一種橫向的網格分割、…

Android Button監聽的方式

Android Button的幾種監聽方式 1、一個Button對應一個監聽 1&#xff09;xml文件中綁定監聽 <Buttonandroid:id"id/btn_test"android:layout_width"match_parent"android:layout_height"wrap_content"android:text"test listener"a…

hdu 5441 (并查集)

題意&#xff1a;給你n個點&#xff0c;m條邊構成無向圖。q個詢問&#xff0c;每次一個值&#xff0c;求有多少條路&#xff0c;路中的邊權都小于這個值 a->b 和 b->a算兩種 思路&#xff1a;把權值從小到大排序&#xff0c;詢問從小到大排序&#xff0c;如果相連則用并查…

【Envi風暴】Envi 5.4遙感影像鑲嵌原來如此簡單!

圖像鑲嵌指是在一定的數學基礎控制下,把多景相鄰的遙感圖像拼接成一個大范圍、無縫圖像的過程。 Envi的圖像鑲嵌功能提供交互式的方式將沒有地理坐標或者地理坐標的多幅圖像合并,生成一幅單一的合成圖像。鑲嵌功能提供了透明處理、勻色、羽化等功能。 下面演示基于地理坐標(…