Rate Limiting в C# (.NET): руководство по библиотеке System.Threading.RateLimiting

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Rate Limiting в C# (.NET): полное руководство по библиотеке System.Threading.RateLimiting

В современных веб-приложениях и микросервисах критически важно контролировать нагрузку на ресурсы. Rate Limiting (ограничение скорости запросов) — это механизм, который предотвращает чрезмерное использование API, баз данных или других компонентов. В экосистеме .NET появилась встроенная библиотека System.Threading.RateLimiting, которая предоставляет гибкие и производительные инструменты для реализации rate limiting. В этой статье мы подробно разберём её возможности, архитектуру и примеры использования.

Что такое System.Threading.RateLimiting?

System.Threading.RateLimiting — это библиотека, входящая в состав .NET 7 и выше. Она предоставляет абстракции и реализации для различных стратегий ограничения скорости. Основной класс — RateLimiter, который управляет доступом к ресурсу, разрешая или отклоняя запросы на основе заданных правил.

Основные концепции

  • RateLimiter — базовый класс, от которого наследуются все реализации.
  • Acquire / TryAcquire — синхронные методы для получения разрешения.
  • AcquireAsync / WaitAsync — асинхронные методы, позволяющие ожидать освобождения лимита.
  • Metadata — дополнительная информация о лимите (например, время до сброса).

Встроенные стратегии Rate Limiting

Библиотека поддерживает четыре основные стратегии:

1. Фиксированное окно (Fixed Window)

Запросы группируются по временным окнам фиксированной длины. Если лимит превышен, запросы отклоняются до начала следующего окна.

using System.Threading.RateLimiting;

var options = new FixedWindowRateLimiterOptions
{
    PermitLimit = 10,
    Window = TimeSpan.FromSeconds(1),
    QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
    QueueLimit = 0
};

var limiter = new FixedWindowRateLimiter(options);

for (int i = 0; i < 15; i++)
{
    using var lease = await limiter.AcquireAsync();
    if (lease.IsAcquired)
    {
        Console.WriteLine($"Запрос {i} выполнен");
    }
    else
    {
        Console.WriteLine($"Запрос {i} отклонён");
    }
}

2. Скользящее окно (Sliding Window)

Аналогично фиксированному, но окно «скользит» с каждым запросом, обеспечивая более плавное ограничение. Разбивается на сегменты (segment).

var slidingOptions = new SlidingWindowRateLimiterOptions
{
    PermitLimit = 10,
    Window = TimeSpan.FromSeconds(1),
    SegmentsPerWindow = 4,
    QueueLimit = 0
};

var slidingLimiter = new SlidingWindowRateLimiter(slidingOptions);

3. Токен бакет (Token Bucket)

Один из самых популярных алгоритмов. Бакет вмещает определённое количество «токенов». Токены добавляются с заданной скоростью. Запрос потребляет один или несколько токенов. Если бакет пуст — запрос ждёт или отклоняется.

var tokenOptions = new TokenBucketRateLimiterOptions
{
    TokenLimit = 100,
    QueueLimit = 0,
    ReplenishmentPeriod = TimeSpan.FromSeconds(1),
    TokensPerPeriod = 10,
    AutoReplenishment = true
};

var tokenLimiter = new TokenBucketRateLimiter(tokenOptions);

4. Конвейер (Concurrency Limiter)

Ограничивает количество одновременно выполняемых запросов. Полезно для управления параллелизмом, а не скоростью.

var concurrencyOptions = new ConcurrencyLimiterOptions
{
    PermitLimit = 5,
    QueueLimit = 10
};

var concurrencyLimiter = new ConcurrencyLimiter(concurrencyOptions);

Использование RateLimiter в ASP.NET Core

Начиная с .NET 7, rate limiting можно легко интегрировать в middleware ASP.NET Core. Регистрация сервисов и настройка политик:

// Program.cs
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("Fixed", config =>
    {
        config.PermitLimit = 10;
        config.Window = TimeSpan.FromSeconds(1);
        config.QueueLimit = 0;
    });

    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});

app.UseRateLimiter();

app.MapGet("/api/resource", async context =>
{
    await context.Response.WriteAsync("Hello from limited API!");
}).RequireRateLimiting("Fixed");

Продвинутые возможности

  • Кастомные политики — можно реализовать собственный RateLimiter, унаследовавшись от базового класса.
  • Партиционирование — создание отдельных лимитов для разных клиентов (IP, API Key

Рекомендаций