성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 정적 분석과 함께, 이제는 실행 시 성능 분석까지 (비록 Azu...
[정성태] .NET Source Browser를 이용해 Roslyn 소스 ...
[정성태] Experimental C# Interceptors: AOT &...
[정성태] .NET Conf 2023 (Day 2) - Tiny, fast...
[정성태] The end of the Tye Experiment #1622...
[정성태] This is a simple app that converts ...
[정성태] Wrathmark: An Interesting Compute W...
[정성태] FFmpeg Filters Every Youtuber Needs...
[정성태] 일단, PInvokeStackImbalance 오류가 발생했다는...
[Heegyoo Lee] 코드 자체는 동작하는 것처럼 보이는데요. (어떤 때는 시그니쳐가...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - 서버 측의 요청 제어 (Microsoft.AspNetCore.RateLimiting)</h1> <p> 닷넷의 경우 공식적으로 Microsoft.AspNetCore.RateLimiting을 통해 ASP.NET Core에서 사용할 수 있는 Middleware를 제공하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Rate limiting middleware in ASP.NET Core ; <a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit'>https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit</a> </pre> <br /> 위의 글을 정리해 사용법을 대충 알아볼까요? ^^<br /> <br /> 이를 위해 기본 ASP.NET Core Web API 프로젝트를 생성하고 Program.cs에 다음과 같이 원하는 요청 제어 코드를 추가할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Microsoft.AspNetCore.RateLimiting; using System.Threading.RateLimiting; namespace WebApplication1 { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); <span style='color: blue; font-weight: bold'>builder.Services.AddRateLimiter(_ => _ .AddFixedWindowLimiter(policyName: "fixed", options => { options.PermitLimit = 4; options.Window = TimeSpan.FromSeconds(5); options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; }));</span> builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); <span style='color: blue; font-weight: bold'>app.UseRateLimiter();</span> // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseAuthorization(); app.MapControllers(); app.Run(); } } } </pre> <br /> <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.ratelimiting.ratelimiteroptionsextensions.addfixedwindowlimiter'>AddFixedWindowLimiter</a>의 옵션 설정은 직관적으로 이해할 수 있습니다. 5초 당 4개의 요청을 허용하고, 요청이 밀리는 경우 최대 2개의 요청만 Queue에 보관하고 있습니다. 예를 들어, 동시 요청이 7개가 오면 4개는 먼저 처리되고, 2개는 Queue에 보관한 다음 1개는 거부를 하는 것입니다.<br /> <br /> 그리고 그런 설정을 대표하는 정책 이름을 "fixed"라고 지정하는데요, 해당 정책을 모든 Web API에 적용하고 싶다면 MapControllers와 연계해 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.ratelimiterendpointconventionbuilderextensions.requireratelimiting'>RequireRateLimiting</a> 확장 메서드를 다음과 같이 호출하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ...[생략]... app.UseAuthorization(); <span style='color: blue; font-weight: bold'>app.MapControllers().RequireRateLimiting("fixed");</span> app.Run(); // ...[생략]... </pre> <br /> <hr style='width: 50%' /><br /> <br /> 자, 그럼 정말 Rate Limit가 잘 적용됐는지 테스트를 해볼까요? ^^ 이를 위해 다음과 같이 간략하게 콘솔 프로젝트를 만들고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > namespace ConsoleApp1; internal class Program { public const int MaxRequests = 7; static async Task<int> Main(string[] args) { var client = new HttpClient(); var requests = new Task<HttpResponseMessage>[MaxRequests]; for (int i = 0; i < MaxRequests; i++) { requests[i] = client.GetAsync("http://localhost:5203/WeatherForecast"); } await Task.WhenAll(requests); for (int i = 0; i < MaxRequests; i++) { Console.WriteLine($"{i}: {requests[i].Result}"); } return 0; } } </pre> <br /> 실행하면 6개의 200 OK 응답과,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Thu, 01 Jun 2023 11:51:53 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/json; charset=utf-8 } </pre> <br /> 1개의 503 응답이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > StatusCode: 503, ReasonPhrase: 'Service Unavailable', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Thu, 01 Jun 2023 11:51:41 GMT Server: Kestrel Content-Length: 0 } </pre> <br /> 결국 4개의 요청은 바로 처리가 되었고, 2개는 Queue에 들어간 후 5초 지난 후에 처리가 되고, 나머지 1개는 요청 초과로 인해 503 오류 코드를 받은 것입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이것으로 기본 사용법은 모두 설명했습니다. 이하 약간의 세부 사항을 들어가 보면!<br /> <br /> 특정 Web API만을 제외하고 싶다면 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.ratelimiting.disableratelimitingattribute'>DisableRateLimiting 특성</a>을 사용할 수 있습니다. 위의 예제 코드에서는 "app.MapControllers().RequireRateLimiting("fixed");" 코드로 전체 서비스에 적용했는데, 특정 API만 제외하고 싶다면 다음과 같이 처리할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; namespace WebApplication1.Controllers; [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { // ...[생략]... <span style='color: blue; font-weight: bold'>[DisableRateLimiting]</span> [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { // ...[생략]... } } </pre> <br /> 혹은, 반대로 RequireRateLimiting("fixed");" 호출을 제거해 모든 API에 대한 요청 제어를 하지 않고, 특정 API만 적용하고 싶다면 <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.ratelimiting.enableratelimitingattribute'>EnableRateLimiting 특성</a>을 사용하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>[EnableRateLimiting("fixed")]</span> // class 수준에도 적용 가능 [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { // ...[생략]... } </pre> <br /> 그 외에, 이제까지 설명한 Limiter는 AddFixedWindowLimiter 메서드의 이름에서 알 수 있듯이 "Fixed Window" 유형이었는데요, 부가적으로 다음과 같은 유형의 요청 제어도 제공하고 있습니다.<br /> <br /> <ul> <li><a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit#slide'>Sliding window</a></li> <li><a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit#token'>Token bucket</a></li> <li><a target='tab' href='https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit#concur'>Concurrency</a></li> </ul> <br /> 위의 기능들을 이용하면, 여러분도 <a target='tab' href='https://platform.openai.com/docs/guides/rate-limits/overview'>OpenAI와 같은 식의 요청 제어</a>를 할 수 있을 것입니다. ^^<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=2089&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1645
(왼쪽의 숫자를 입력해야 합니다.)