ASP.NET Core 7 - Usando Rate Limiting
Neste artigo vou apresentar o novo recurso nativo da ASP .NET Core 7 : o middleware Rate Limiting. |
O termo
Rate
Limiting, traduzido literalmente, significa limitação de taxa, e, em aplicações ASP
.NET Core esta relacionado com limitar o número de requests que podem ser feitos
em um período de tempo.
Assim, a limitação
de taxa é uma forma de controlar a quantidade de tráfego que uma aplicação MVC
ou Web ou API, limitando o número de request que podem ser feitas em um
determinado período de tempo. Isso pode ajudar a melhorar o desempenho do site
ou aplicativo e evitar que ele pare de responder.
A partir do .NET 7, a ASP.NET Core inclui um middleware integrado de limitação
de taxa, que pode ser usado para limitar a taxa de aplicativos para Web.
Neste artigo veremos como configurar e usar o middleware de limitação de taxa na ASP.NET Core.
Rate Limiting
Cada aplicativo
que você constrói está compartilhando recursos. O aplicativo é executado em um
servidor que compartilha sua CPU, memória e E/S de disco, em um banco de dados
que armazena dados de todos os seus usuários.
Quer sejam acidentais ou intencionais, os usuários podem exaurir esses recursos
de uma forma que afete os demais usuários. Um script pode fazer muitas
solicitações ou uma nova implantação da sua aplicação pode estar chamando uma
API específica muitas vezes e isso resultar na lentidão do banco de dados. Por
padrão todos os seus usuários obtêm acesso a uma quantidade igual de recursos
compartilhados, dentro do limite do que seu aplicativo pode suportar.
Digamos que o banco de dados usado por seu aplicativo possa manipular com
segurança cerca de 1.000 consultas por minuto. Em seu aplicativo, você pode
definir um limite para permitir apenas 1.000 solicitações por minuto para evitar
que o banco de dados receba mais solicitações.
Em vez de um limite global de “1.000 solicitações por minuto”, você pode
observar o uso médio do aplicativo e, por exemplo, definir um limite de “100
solicitações por usuário por minuto”. Ou encadear esses limites e definir a
limitação como: “100 solicitações por usuário por minuto e 1000
solicitações por minuto”.
Os limites de taxa vão ajudar a evitar que o servidor seja sobrecarregado
por muitas solicitações e ainda garante que todos os usuários tenham uma chance
justa de obter suas solicitações processadas.
Usando o middleware Rate Limite
Em aplicações que usam o .NET 7 (ou superior), agora existe um middleware de limitação de taxa disponível e pronto para uso, e, ele fornece uma maneira de aplicar a limitação de taxa ao seu aplicativo da Web e aos endpoints da sua API.
Da mesma forma que é feita para outros middlewares, para habilitar o middleware Rate Limiting da ASP.NET Core, teremos que adicionar os serviços necessários à coleção de serviços e, em seguida, habilitar o middleware para todos os pipelines de solicitação.
A configuração é feita na classe Program usando o método AddRateLimiter para um objeto builder.Services onde podemos definir algumas propriedades para o Rate Limiting através dos métodos de extensão da classe RateLimiterOptionsExtensions.
Existem vários algoritmos diferentes que podem ser usados com a limitação da taxa para controlar o fluxo de requisições. Atualmente no .NET 7 são fornecidos os seguintes controles:
É a forma mais simples de limitação de taxa. Ele não olha para o tempo, apenas para o número de solicitações simultâneas : “Permitir 10 solicitações simultâneas”.
O limite de balde de token permite controlar a taxa de fluxo e permite rajadas. Pense “você recebe 100 requests a cada minuto”, se você fizer todas elas em 10 segundos, terá que esperar 1 minuto antes poder fazer mais requests.
Além disso podemos definir algumas propriedades para o Rate Limiting como :
Assim considerando apenas os algorítmos Fixed Window Limit e Sliding Window Limit podemos fazer a seguinte configuração na classe Program:
Exemplo de configuração:
using ApiRateLimiting.Services;
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
...
builder.Services.AddRateLimiter(_ => _
.AddFixedWindowLimiter(policyName: "LimiterPolicy", options =>
{
options.PermitLimit = 1;
options.Window = TimeSpan.FromSeconds(10); // Permite apenas 1 a cada 10 segundos
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; //obtem o mais antigo da fila
options.QueueLimit = 3; // Enfileira apenas 3 request quando o limite for ultrapassado
}).
.AddSlidingWindowLimiter("sliding", options =>
{
options.PermitLimit = 5;
options.Window = TimeSpan.FromSeconds(10);
options.SegmentsPerWindow = 5;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = 2;
}));
var app = builder.Build();
app.UseRateLimiter();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();
|
Vamos entender o código:
A chamada para builder.Services.AddRateLimiter(...) registra o middleware ASP.NET Core com a coleção de serviços, incluindo suas opções de configuração. Há muitas opções que podem ser especificadas, como o código de status HTTP que está sendo retornado, o que deve acontecer quando a limitação de taxa se aplica e políticas adicionais.
Neste exemplo, estamos adicionando um AddFixedWindowLimiter e um AddSlidingWindowLimiter e usando as propriedades para configuramos cada rate limiting usando o policyName, que é o identificador da política de Rate Limiting especificado, e que precisará ser passado no momento de atribuir ao Controller ou Action, como será feito posteriormente;
O
FixedWindowLimiter é então configurado para
reabastecer automaticamente as solicitações permitidas e permite “1 request a
cada 10 segundos” e o SlidingWindowLimiter é configurado para permitir '5
requests por segundo'.
Após
configurar os Rate Limiters, é necessário chamar
app.UseRateLimiter() para poder usar o recurso.
Para mostrar um exemplo prático vamos criar uma Web Api ASP .NET Core no .NET 7.0 usando o VS 2022 Community com o nome ApiRateLimiting.
recursos usados:
Criando o projeto API
Abra o VS 2022 e acione o menu Create New Project;
Na janela Add New Project selecione o template ASP.NET Core Web API informe o nome ApiRateLimiting e a seguir defina as seguintes configurações para criar o projeto:
Não vamos habilitar o Swagger e vamos usar controladores no projeto.
Crie no projeto a pasta Services e nesta pasta crie a classe a interface IHoraAtualService que representa nosso modelo de domínio:
namespace
ApiRateLimiting.Services; public interface IHoraAtualService{ TimeOnly HoraAtual(); } |
Nesta interface definimos um contrato usando o recurso da struct TimeOnly.
A seguir na mesma pasta crie a classe HoraAtualService que implementa esta interface:
public
class
HoraAtualService :
IHoraAtualService { public HoraAtualService() {} public TimeOnly HoraAtual() { return TimeOnly.FromDateTime(DateTime.Now); } } |
Agora vamos configurar o middleware Rate Limiting na classe Program:
using
ApiRateLimiting.Services; using Microsoft.AspNetCore.RateLimiting; using System.Threading.RateLimiting; var builder = WebApplication.CreateBuilder(args);// Add services to the container. builder.Services.AddScoped<IHoraAtualService, HoraAtualService>(); builder.Services.AddRateLimiter(_ => _ { options.PermitLimit = 1; options.Window = TimeSpan.FromSeconds(10); // Permite apenas 1 a cada 10 segundos options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; //obtem o mais antigo da fila options.QueueLimit = 3; // Enfileira apenas 3 request quando o limite for ultrapassado })); var app = builder.Build();app.UseRateLimiter(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.MapControllers(); app.Run(); |
Registramos o serviço e configuramos o middleware para o Rate Limiting.
A seguir vamos criar na pasta Controllers o controlador HoraAtualController onde vamos usar o atributo EnableRateLimiting na Action:
using
Microsoft.AspNetCore.RateLimiting; namespace ApiRateLimiting.Controllers;[Route( "api/[controller]")][ApiController] public class HoraAtualController : ControllerBase { IHoraAtualService _servico; public HoraAtualController(IHoraAtualService servico) { _servico = servico; } [HttpGet] public IActionResult Index() { return Ok(_servico.HoraAtual()); } } |
Executando o projeto iremos obter a hora atual:
Se tentarmos executar um segundo request logo a seguir veremos que isso não será feito imediatamente mas somente após 10 segundos conforme a politica definida na configuração do Rate Limiting.
Pegue o projeto aqui: ApiRateLimiting.zip ...
"Regozijai-vos sempre.
Orai sem cessar.
Em tudo dai
graças, porque esta é a vontade de Deus em Cristo Jesus para convosco."
1 Tessalonicenses
5:16-18
Referências:
NET - Unit of Work - Padrão Unidade de ...