Ограничение скорости — это метод, используемый для ограничения количества запросов, разрешенных к определенному ресурсу в определенное временное окно, для предотвращения DDoS-атак и злоупотреблений API. При достижении порога ограничения скорости последующие запросы к ресурсу запрещаются, задерживаются или регулируются.
В предыдущей статье я рассказал, как начать работу с новым промежуточным программным обеспечением для ограничения скорости в ASP.NET Core 7. В этой статье я рассмотрю четыре различных алгоритма ограничения скорости, доступные в ASP.NET Core 7: фиксированное окно, скользящее окно, ведро маркеров и параллелизм.
Чтобы использовать примеры кода, представленные в этой статье, в вашей системе должна быть установлена Visual Studio 2022. Если у вас еще нет копии, вы можете скачать Visual Studio 2022 здесь.
Создайте минимальный проект веб-API ASP.NET Core в Visual Studio 2022.
Прежде всего, давайте создадим минимальный проект веб-API ASP.NET Core 7 в Visual Studio 2022. Выполните следующие действия:
- Запустите интегрированную среду разработки Visual Studio 2022.
- Нажмите «Создать новый проект».
- В окне «Создать новый проект» выберите «ASP.NET Core Web API» из списка отображаемых шаблонов.
- Нажмите “Далее.
- В окне «Настроить новый проект» укажите имя и расположение нового проекта.
- При желании установите флажок «Поместить решение и проект в один каталог», в зависимости от ваших предпочтений.
- Нажмите “Далее.
- В следующем окне «Дополнительная информация» выберите «NET 7.0 (Current)» в качестве платформы. Снимите флажок «Использовать контроллеры…», так как в этом примере мы будем использовать минимальные API. Оставьте для параметра «Тип аутентификации» значение «Нет» (по умолчанию).
- Убедитесь, что все флажки «Включить Docker», «Настроить для HTTPS» и «Включить поддержку Open API» сняты. Мы не будем использовать ни одну из этих функций здесь.
- Щелкните Создать.
Мы будем использовать этот проект веб-API ASP.NET Core 7 для создания минимального API и реализации четырех различных алгоритмов ограничения скорости в следующих разделах.
Реализовать контроллер в ASP.NET Core 7.
Давайте реализуем контроллер, чтобы продемонстрировать, как работает ограничение скорости в ASP.NET Core. Для этого выберите папку решения Controllers вашего проекта и нажмите Add -> Controller. Выберите шаблон «Контроллер API — пустой» из списка шаблонов, отображаемых в окне «Добавить шаблон», и введите имя. для контроллера при появлении запроса. Затем замените код по умолчанию следующим.
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { [HttpGet] public string Get() { return "Hello World"; } [HttpGet("{id}")] public string Get(int id) { return $"The value of id is: {id}"; } }
Абстрактный базовый класс RateLimiter в ASP.NET Core 7.
До ASP.NET Core 7 ограничение скорости было доступно как часть пространства имен Microsoft.AspNetCore.RateLimiting. Ограничение скорости в ASP.NET Core 7 теперь доступно как часть пространства имен System.Threading.RateLimiting.
Основным типом является абстрактный базовый класс RateLimiter, обладающий несколькими замечательными свойствами. Абстрактный класс RateLimiter выглядит следующим образом:
public abstract class RateLimiter : IAsyncDisposable, IDisposable { public abstract RateLimiterStatistics? GetStatistics(); public abstract TimeSpan? IdleDuration { get; } public RateLimitLease AttemptAcquire(int permitCount = 1); protected abstract RateLimitLease AttemptAcquireCore(int permitCount); public ValueTask<RateLimitLease> AcquireAsync(int permitCount = 1, CancellationToken cancellationToken = default); protected abstract ValueTask<RateLimitLease> AcquireAsyncCore(int permitCount, CancellationToken cancellationToken); protected virtual void Dispose(bool disposing); public void Dispose(); protected virtual ValueTask DisposeAsyncCore(); public async ValueTask DisposeAsync(); }
Обратите внимание, что здесь представлены только объявления методов. Определения методов опущены для краткости.
Настройка ограничения скорости в ASP.NET Core 7
Чтобы настроить ПО промежуточного слоя для ограничения скорости в ASP.NET Core 7, вы используете метод AddRateLimiter. Чтобы добавить ПО промежуточного слоя для ограничения скорости в приложение ASP.NET Core 7, вы сначала добавляете необходимые службы в контейнер, как показано во фрагменте кода, приведенном ниже.
builder.Services.AddRateLimiter(options =>{ //Write your code to configure the middleware here});
Чтобы добавить ПО промежуточного слоя в конвейер, вы вызываете метод расширения UseRateLimiter, как показано ниже.
app.UseRateLimiter();
Вы можете настроить RateLimiter с несколькими параметрами, включая максимально допустимое количество запросов, код состояния ответа и временное окно. Вы также можете определить ограничение скорости на основе метода HTTP, IP-адреса клиента и других факторов. Кроме того, вы можете ставить запросы в очередь вместо того, чтобы отклонять их.
Алгоритмы ограничения скорости в ASP.NET Core 7
Пакет System.Threading.RateLimiting обеспечивает поддержку следующих алгоритмических моделей:
- Фиксированное окно
- Раздвижное окно
- Сегмент токенов
- параллелизм
Фиксированное окно
Алгоритм фиксированного окна допускает фиксированное количество запросов в течение определенного временного окна, а все последующие запросы регулируются. Основываясь на требовании ограничения скорости, этот алгоритм делит время на фиксированные окна. Например, предположим, что вы хотите разрешить 10 запросов в минуту. Как только этот предел будет достигнут, последующие запросы будут отклонены до сброса окна.
В следующем фрагменте кода показано, как можно настроить ограничитель фиксированной скорости окна в файле Program.cs в ASP.NET Core 7.
builder.Services.AddRateLimiter(options => { options.RejectionStatusCode = 429; options.AddFixedWindowLimiter(policyName: "fixed", options => { options.PermitLimit = 3; options.Window = TimeSpan.FromSeconds(10); options.AutoReplenishment = true; options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; }); });
Метод AddLimiter используется для добавления служб ограничения скорости в контейнер служб. Метод AddFixedWindowLimiter используется для добавления политики фиксированного окна. Имя политики указано здесь как «фиксированное». Обратите внимание на значения свойств PermitLimit и Window. Установив PermitLimit на 3 и Window на 10, вы разрешаете максимум три запроса каждые 10 секунд.
Когда вы запускаете приложение и вызываете конечную точку чаще, чем допустимое ограничение, по умолчанию будет возвращен код состояния HTTP 503 «Служба недоступна». Просто измените RejectionStatusCode, чтобы он возвращал другой код состояния. В приведенном выше примере свойство RejectionStatusCode настроено на возврат кода состояния HTTP 429 «Слишком много запросов».
Кроме того, QueueProcessingOrder указывается как OldestFirst, а QueueLimit имеет значение 2. Таким образом, последующие два запроса будут регулироваться и сохраняться в очереди всякий раз, когда будет превышено ограничение окна. Затем самый старый запрос будет выбран из очереди и обработан.
Раздвижное окно
Подобно фиксированному окну, алгоритм скользящего окна допускает фиксированное количество запросов за временное окно. Разница в том, что скользящее окно делит временное окно на сегменты. На каждом интервале сегмента окно сдвигается на один сегмент.
Интервал сегмента равен времени окна, деленному на количество сегментов в окне. Итак, если ваше окно составляет 60 секунд, и вы указываете два сегмента, временное окно будет сдвигаться каждые 30 секунд.
В следующем фрагменте кода показано, как можно настроить ограничитель скорости скользящего окна в файле Program.cs в ASP.NET Core 7.
builder.Services.AddRateLimiter(options => { options.RejectionStatusCode = 429; options.AddSlidingWindowLimiter(policyName: "sliding", options => { options.PermitLimit = 30; options.Window = TimeSpan.FromSeconds(60); options.SegmentsPerWindow = 2; options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; }); });
Свойство SegmentsPerWindow используется для указания количества сегментов во временном окне.
Сегмент токенов
В алгоритме корзины токенов каждый токен в корзине представляет собой запрос. Маркер удаляется из корзины всякий раз, когда обслуживается запрос. Если ведро становится пустым, следующий запрос отклоняется или регулируется. Со временем ведро наполняется с фиксированной скоростью.
Рассмотрим пример, когда ведро имеет ограничение в 10 токенов. Когда приходит запрос и доступен токен, запрос будет обслуживаться, а количество токенов уменьшается. Если лимит токенов превышен, а токенов не осталось, запросы будут отклонены или ограничены.
В следующем примере кода показано, как настроить ограничитель скорости токена в файле Program.cs в ASP.NET Core 7.
builder.Services.AddRateLimiter(options => { options.RejectionStatusCode = 429; options.AddTokenBucketLimiter(policyName: "token", options => { options.TokenLimit = 2; options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; options.ReplenishmentPeriod = TimeSpan.FromSeconds(10); options.TokensPerPeriod = 2; options.AutoReplenishment = true; }); });
Свойство TokenLimit указывает максимальное количество токенов, которое может храниться в корзине в любой момент времени.
параллелизм
Ограничитель параллелизма контролирует максимальное количество одновременных запросов к ресурсу. Если вы установите ограничение, например, 10, только первым 10 запросам будет предоставлен доступ к ресурсу в данный момент времени. Всякий раз, когда запрос завершается, он открывает слот для нового запроса.
В следующем фрагменте кода показано, как настроить ограничитель скорости параллелизма в ASP.NET Core 7.
builder.Services.AddRateLimiter(options => { options.RejectionStatusCode = 429; options.AddConcurrencyLimiter(policyName: "concurrency", options => { options.PermitLimit = 3; options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; options.QueueLimit = 2; }); });
Включить или отключить ограничение скорости в ASP.NET Core 7
Вы можете применить ограничение скорости к контроллеру, методу действия или странице Razor. [EnableRateLimiting] и [DisableRateLimiting] Атрибуты можно использовать для включения или отключения ограничения скорости в ASP.NET Core 7.
В следующем листинге кода показано, как можно применить «фиксированный» ограничитель скорости к DefaultController, который мы создали ранее, и отключить ограничение скорости в методе действия того же контроллера.
[Route("api/[controller]")] [ApiController] [EnableRateLimiting("fixed")] public class DefaultController : ControllerBase { [HttpGet] public string Get() { return "Hello World"; } [HttpGet("{id}")] [DisableRateLimiting] public string Get(int id) { return $"The value of id is: {id}"; } }
Ограничение скорости имеет ряд преимуществ. Он может защитить ваши приложения или API-интерфейсы от отказа в обслуживании и других злонамеренных атак, а также от незлонамеренного чрезмерного использования. Уменьшая объем запросов в определенное временное окно и, таким образом, сокращая сетевой трафик и снижая затраты на инфраструктуру. Наконец, это может даже повысить производительность вашего приложения, обеспечив справедливое использование доступных ресурсов.
В следующей статье на эту тему я расскажу, как мы можем реализовать пользовательские политики ограничения скорости в ASP.NET Core 7.