Microsoft biedt sinds .NET 7 ingebouwde ondersteuning voor rate limiting. Rate limiting is, mits juist toegepast, een effectieve manier om een webapplicatie te beschermen tegen extreme gebruikspieken.

Als onderdeel van de Microsoft.AspNetCore.RateLimiting package kun je heel eenvoudig rate limiting toepassen.

Fixed window limiter

De fixed window limiter gebruikt een vaste tijdspanne om een maximum aantal requests toe te staan.

builder.Services.AddRateLimiter(_ => _
 .AddFixedWindowLimiter(policyName: “fixed”, options =>
 {
  options.PermitLimit = 4;
  options.Window = TimeSpan.FromSeconds(12);
  options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
  options.QueueLimit = 2;
 }));
 
var app = builder.Build();
 
app.UseRateLimiter();
 
 

In het voorbeeld hierboven is er een maximum van 4 requests per 12 seconden ingesteld. De queue limit geeft aan hoeveel berichten er in de wacht gezet worden voordat de applicatie een 503 status teruggeeft.

Het toepassen van de rate limit is zo eenvoudig als het toevoegen van een attribute in je controller method:

[EnableRateLimiting(“fixed”)]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
 return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
  Date = DateTime.Now.AddDays(index),
  TemperatureC = Random.Shared.Next(-20, 55),
  Summary = Summaries[Random.Shared.Next(Summaries.Length)]
 })
 .ToArray();
}
 
 

Of als je minimal api’s gebruikt, het configureren van de limit op de mapping van je endpoints:

app.MapGet(“/”, () => Results.Ok($”Hello {GetTicks()}”))
.RequireRateLimiting(“fixed”);
 
 

Sliding window limiter

builder.Services.AddRateLimiter(_ => _
.AddSlidingWindowLimiter(policyName: slidingPolicy, options =>
{
options.PermitLimit = 4;
options.Window = TimeSpan.FromSeconds(12);
options.SegmentsPerWindow = 3;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = 2;
}));
 

De sliding window limiter lijkt veel op de fixed window limiter, maar gebruikt op basis van de SegmenstPerWindow een dynamisch tijdslot. In het voorbeeld hierboven zijn er 4 requests per 12 seconden toegestaan, maar het tijdslot van 12 seconden is verdeeld in drie segmenten. Dat betekent dat elke 4 seconden het tijdslot meebeweegt.

Token bucket limiter

builder.Services.AddRateLimiter(_ => _
 .AddTokenBucketLimiter(policyName: tokenPolicy, options =>
  {
  options.TokenLimit = myOptions.TokenLimit;
  options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
  options.QueueLimit = myOptions.QueueLimit;
  options.ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.ReplenishmentPeriod);
  options.TokensPerPeriod = myOptions.TokensPerPeriod;
  options.AutoReplenishment = myOptions.AutoReplenishment;
 }));
 

De token bucket limiter lijkt veel op de sliding window limiter, maar gebruikt in plaats van requests als limiter mechanisme tokens. Elk request verbruikt een token. De token bucket limiter biedt wat meer configuratie mogelijkheden dan de sliding window limiter.

Concurrency limiter

builder.Services.AddRateLimiter(_ => _
 .AddConcurrencyLimiter(policyName: concurrencyPolicy, options =>
  {
  options.PermitLimit = myOptions.PermitLimit;
  options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
  options.QueueLimit = myOptions.QueueLimit;
 }));
 

De concurrency limiter zorgt dat er maar een beperkt aantal gelijktijdige request kan worden gedaan.

Aangepaste response configuratie

Standaard geeft de rate limiting middleware een http-statuscode 503 als resultaat. Dat is mogelijk niet het resultaat dat je terug wilt geven aan gebruikers van je applicatie. Je kunt vrij eenvoudig het resultaat aanpassen door opties mee te geven aan je rate limiting configuratie:

builder.Services.AddRateLimiter(options =>
{
 options.OnRejected = async (context, token) =>
  {
  context.HttpContext.Response.StatusCode = 429;
  await context.HttpContext.Response.WriteAsync(
  “Too many requests. Read more about our rate limits at
  https://example.org/docs/ratelimiting.”,
  cancellationToken: token);
  };
 
// …
 });
 
 

Dus…

Het is heel eenvoudig om rate limiting toe te passen op een webapplicatie in .NET. Alle reden om eens in te duiken, want een goed ingestelde rate limiting voorkomt veel problemen.

In een volgend artikel gaan we in op Api Management in de cloud. Het nadeel van rate limiting in je code is namelijk dat je extra logica in code nodig hebt. Met Api Management kun je dit soort functionaliteit ook buiten je eigen applicatie faciliteren.