Выходные прошли, рабочие дни вернулись, и я подготовила технический пост.
В посте про API Gateway упоминалось, что одной из его функций является rate limiting. Предлагаю сегодня разобраться с этим подробнее.
🫧 Что такое Rate Limiter
Rate Limiter — это механизм, который контролирует количество запросов, которые система может обработать за определённый промежуток времени. Его задача заключается в защите ресурсов от чрезмерной нагрузки при массовых обращениях к API.
В настройках рейт лимитера задают лимиты количества запросов в единицу времени. Например, у нас есть публичное API, на которое могут обращаться авторизованные пользователи, и мы настраиваем лимит 20 запросов/сек от одного пользователя. Определять пользователя можно по JWT токену, по IP, по API-ключу.
Пока заданный лимит не исчерпан, рейт лимитер передает запрос дальше на бэк.
Если лимит превышен, рейт лимитер не пропускает запрос и отдает ошибку
429 Too Many Requests.Rate limiter предназначен для ограничения количества запросов от "хороших" клиентов, чтобы конкретный клиент не перегрузил сервис. При суровой DDoS-атаке только он не спасет, так как атака может идти с тысяч разных IP-адресов.
🫧 Место Rate Limiter в микросервисной архитектуре
Почти все современные API Gateway имеют встроенные механизмы rate limiting, но иногда рейт лимитер выносят в отдельный сервис, к которому уже обращается API Gateway.
Рейт лимитеру нужно хранить состояние, чтобы посчитать, сколько запросов уже было за период. Эти данные он может хранить у себя в памяти или в отдельном хранилище (например, Redis). Отдельное хранение нужно, когда используется несколько инстансов API Gateway. Redis помогает обеспечить атомарность операций, чтобы все инстансы гейтвеев видели общее состояние, и не возникало гонок и рассинхронизации.
🫧 Алгоритмы rate limiting
🤍 Fixed window (фиксированное окно)
Как работает:
Представим, что у нас есть лимит 10 запросов в минуту. Например: 09:00:00 → 09:00:59 — это одно окно.
Окно не обязано быть минутой, это может быть и 10 миллисекунд.
Считаем, сколько запросов пришло в этом окне.
Пока запросов меньше 10 → пропускаем их ✅
Если уже больше 10 → отклоняем ❌
Когда наступает новая минута — счётчик сбрасывается.
Проблема fixed window заключается во всплесках (burst) на границе окон: если пришло 10 запросов в 09:00:59, а потом еще 10 запросов в 09:01:01, то получается 20 запросов за 2 секунды, а должно быть не больше 10 в минуту.
🤍 Sliding window (скользящее окно)
Этот алгоритм решает проблему со всплесками на границе окон.
Как работает:
Если лимит 10 запросов в минуту, то храним временные метки всех запросов за последние 60 секунд.
На практике это оптимизируют, чтобы не хранить всё.
Для каждого запроса проверяем, сколько за последние 60 секунд уже пришло запросов от этого пользователя.
Если прошлых запросов меньше 10 → пропускаем ✅
Если за последние 60 секунд уже было 10 запросов → отклоняем ❌
Запросы старше 60 секунд убираем из списка.
Sliding window обеспечивает равномерное распределение, но у него выше требования к памяти (нужно хранить временные метки запросов) и выше вычислительная сложность (нужно перебирать и удалять устаревшие временные метки из списка).
Давайте посмотрим более гибкий алгоритм, который используется во многих API Gateway ⬇️
