ASP.NET Core - Rate limiting
Rate limiting je technika používaná hlavne pri API na kontrolu a obmedzenie počtu požiadaviek, ktoré môžu klienti vykonať na API v definovanom čase.
Patrí do skupiny Resiliences paternov, ktoré zabezpečujú, že API zostane stabilné a dostupné pre všetkých používateľov, čím sa predchádza zneužitiu alebo nadmernému využitiu, ktoré by mohlo ohroziť jeho výkon.
V minulosti sa v ASP.NET Core na rate limiting používala knižnica AspNetCoreRateLimit. Od verzie .NET 7 je v ASP.NET Core rate limiting dostupný priamo v rámci frameworku.
Vyberte si jeden z dostupných algoritmov rate limitingu:
- Fixed window
- Sliding window
- Token bucket
- Concurrency
💁 Jednotlivé metódy nájdeš detailne vysvetlené priamo v dokumentácii.
Najskôr zaregistruj policy:
builder.Services.AddRateLimiter(limiter =>
{
// 👇 Define the status code to be returned when the request is rejected.
limiter.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
// 👇 Define the policy.
limiter.AddFixedWindowLimiter(policyName: "products", options =>
{
options.PermitLimit = 10;
options.Window = TimeSpan.FromSeconds(1);
// 👇 If you want to use a queue to process requests that exceed the limit, you can set the following options.
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = 4;
});
});
Následne pridaj middleware do pipeline:
app.UseRateLimiter();
A použite policy pri definícií endpointu:
app.MapGet("/products", () =>
{
return new string[] { "product1", "product2", "product3", "product4" };
}).RequireRateLimiting("products"); // 👈 Add the policy to endpoint.
Pokiaľ máme definovanú policy na celej skupine endpointov, môžete potom disablovať rate limiting pre konkrétny endpoint:
var group = app.MapGroup("/api/products")
.RequireRateLimiting("products");
group.MapGet("/", () =>
{
return new string[] { "product1", "product2", "product3", "product4" };
}).DisableRateLimiting(); // 👈 Disable the policy for the endpoint.
V prípade controllerov môžete použiť atribúty [EnableRateLimiting(...)]
a [DisableRateLimiting]
.
[EnableRateLimiting("products")]
public class ProductsController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "product1", "product2", "product3", "product4" };
}
[DisableRateLimiting]
[HttpGet("{id}")]
public string Get(int id)
{
return "product";
}
}
Multitenancy
Ak staviate multi-tenant systém, tak pravdepodobne chcete mať rate limiting pre pre každého tenant-a. Napríklad chcete aby tenant mohol vykonať 10 požiadaviek za sekundu. Prípadne chcete mať rôzne limity pre rôzne tenant-y. Toto je možné dosiahnuť pomocou RateLimitPartition
triedy.
builder.Services.AddRateLimiter(limiter =>
{
// 👇 Define custom policy.
limiter.AddPolicy("fixed-by-tenant",
context => RateLimitPartition
.GetFixedWindowLimiter(
context.Request.Headers["tenant-id"], // 👈 Get tenant id
_ => new FixedWindowRateLimiterOptions
{
Window = TimeSpan.FromSeconds(1),
PermitLimit = 10
}));
// 👇 If you want different policy per tenant
limiter.AddPolicy("fixed-by-tenant-2",
context => RateLimitPartition
.GetFixedWindowLimiter(
context.Request.Headers["tenant-id"], // 👈 Get tenant id
tenantId => GetOptionsByTenant(tenantId)));
// 👆 Get options by tenan from your configuration
});