Обновлено: 23 июня 2026 г. в 00:45

Rate Limiter

средний

Классический кейс про лимитер запросов: выбор алгоритма, хранение счётчиков в Redis и определение точки применения лимита в распределённой системе.

Лимитер запросов кажется задачей про счётчик, но на деле это кейс про справедливое распределение ресурса, всплески нагрузки и поведение системы в момент отказа защитного слоя.

Глава помогает сравнить алгоритмы на основе токенов, протекающего ведра и скользящего окна, выбрать точку применения лимита, способ хранения счётчиков и режим работы при сбоях.

В интервью и архитектурных обсуждениях этот кейс быстро показывает, умеете ли вы рассуждать о злоупотреблениях, критическом пути и цене неудачной политики по умолчанию.

Контур управления

Фокус на политиках управления, лимитах, маршрутизации и стабильном поведении на границе системы.

Путь данных

Нужно держать предсказуемую задержку и пропускную способность при росте трафика и всплесках нагрузки.

Режимы отказа

Покрывайте блокирующее и пропускающее поведение, деградацию и безопасный резервный сценарий при частичных отказах.

Готовность к эксплуатации

Показывайте мониторинг насыщения, шторм повторных попыток и операционные защитные ограничения.

Ограничитель запросов — классический кейс про защиту публичного API и справедливое распределение ресурса. На поверхности это просто счётчик запросов, но на практике приходится решать, где именно применять лимит, как хранить состояние между инстансами и что делать, если сам лимитер начинает ошибаться или недоступен.

На интервью эта задача быстро упирается в : насколько точно держать ограничение, сколько добавить на критический путь и как вести себя, когда отказывает сам защитный слой. Каждый из этих вопросов тянет за собой цену.

Глава 4

Alex Xu: Rate Limiter

Подробный разбор алгоритмов и архитектурных решений в книге

Читать обзор

Зачем нужен лимитер запросов

Что происходит без лимитов

  • Распределённые атаки отказа в обслуживании — перегрузка сервиса вредоносным трафиком
  • Каскадные отказы — один источник трафика может перегрузить весь сервис
  • Перерасход ресурсов — бесконтрольное потребление API
  • Неравномерная нагрузка — «шумные соседи» отъедают ресурс у остальных

Что даёт лимитер запросов

  • Защита сервисов — предотвращение перегрузки
  • Справедливое распределение — квоты для каждого клиента
  • Экономия денег — контроль использования платных API
  • Предсказуемость — стабильная производительность

Типичные требования

Функциональные

  • FR1
    Ограничение запросов по IP-адресу, идентификатору пользователя или API-ключу
  • FR2
    Настраиваемые лимиты для разных эндпоинтов
  • FR3
    Информативный ответ при превышении лимита (429)
  • FR4
    Работа в распределённой среде

Нефункциональные

  • NFR1
    Низкая задержка — меньше 1 мс дополнительного времени на запрос
  • NFR2
    Высокая доступность — сбой лимитера ≠ сбой сервиса
  • NFR3
    Точность лимитов (допустима погрешность до ±5% в распределённой среде)
  • NFR4
    Горизонтальное масштабирование

Алгоритмы ограничения запросов

У каждого классического алгоритма свой профиль точности, памяти и поведения под всплесками нагрузки:

Интерактивная визуализация

1. Token Bucket

Бакет с токенами пополняется с постоянной скоростью. Каждый запрос забирает один токен.

Преимущества

  • Простая реализация
  • Хорошо переживает всплески нагрузки
  • Экономно расходует память (два числа на пользователя)

Недостатки

  • Непросто выбрать размер бакета
  • В распределённой среде возможны гонки при обновлении счётчиков

# Параметры:

bucket_size = 10 # максимум токенов

refill_rate = 2 # скорость пополнения

Визуализация алгоритма

Токены:
5.0 / 5
Пополнение: 1 ток./сек
t = 0.0s
История запросов:
Нажмите "Старт" и отправляйте запросы

Архитектура решения

Связанный кейс

API Gateway

Полный разбор шлюза API: маршрутизация, безопасность, клиентский фасад и сравнение технологий.

Читать кейс

Где лучше ставить лимитер запросов?

На стороне клиента

Клиент контролирует только сам себя, а значит лимит легко обойти. Годится как ранний отсев лишних запросов, но не как защита.

Шлюз API

Самая удобная точка: единый вход в систему перед прикладными сервисами. Например, управляемый шлюз AWS, Kong или Envoy.

Внутри сервиса

Гибко по правилам, но цена — дублирование логики в каждом сервисе и более сложная синхронизация счётчиков.

Zhiyong Tan

Acing SDI: Rate Limiter

Сравнение вариантов размещения лимитера в реальных системах

Читать обзор

Реализация на базе Redis

Счётчик лимита читают и обновляют на каждом запросе, поэтому хранилище должно быть быстрым и не ломаться при параллельном доступе. Redis закрывает оба требования: данные в памяти и атомарные операции.

Счётчик скользящего окна на Redis

-- Lua-скрипт для атомарного обновления
local key = KEYS[1]
local window = tonumber(ARGV[1])  -- размер окна в секундах
local limit = tonumber(ARGV[2])   -- лимит запросов
local now = tonumber(ARGV[3])     -- текущая метка времени

-- Удаляем устаревшие записи
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)

-- Считаем запросы в текущем окне
local count = redis.call('ZCARD', key)

if count < limit then
    -- Добавляем новый запрос
    redis.call('ZADD', key, now, now .. '-' .. math.random())
    redis.call('EXPIRE', key, window)
    return 1  -- запрос разрешён
else
    return 0  -- запрос отклонён
end

Защита от гонок

Проблема: Параллельные запросы могут одновременно увидеть одно и то же значение счётчика.

Решение: Lua-скрипты выполняются в Redis атомарно.

Альтернатива: Redis MULTI/EXEC или Redlock, если нужна распределённая блокировка.

Синхронизация между инстансами

Централизованный вариант: Один Redis-кластер обслуживает все инстансы приложения.

Согласованность в конечном счёте: Локальные счётчики с периодической синхронизацией.

Компромисс: Точность против задержки.

Заголовки ответа

# При успешном запросе:

X-RateLimit-Limit: 100

X-RateLimit-Remaining: 42

X-RateLimit-Reset: 1640995200

# При превышении лимита:

HTTP/1.1 429 Too Many Requests

Retry-After: 30

Глубже: многоуровневые лимиты

В реальных системах лимиты почти всегда задают на нескольких уровнях одновременно:

Уровни лимитов

  • Глобальный: 10 млн запросов в сутки на весь сервис
  • На пользователя: 1000 запросов в час
  • На эндпоинт: 100 запросов в минуту на `/api/search`
  • На IP-адрес: защита от перегрузки с одного источника

Мягкая деградация

  • Мягкий лимит: предупреждение в заголовках ответа
  • Жёсткий лимит: ответ `429` и заголовок с временем повторной попытки
  • Сбой Redis: пропускать запросы или, наоборот, блокировать их?
  • Наблюдаемость: оповещения об аномалиях трафика

Что важно проговорить на интервью

  • 1
    Начните с требований: какой профиль трафика, допустима ли погрешность и нужна ли работа в распределённой среде?
  • 2
    Выберите алгоритм: токеновое ведро подходит для всплесков, счётчик скользящего окна — когда нужна более точная оценка текущей нагрузки.
  • 3
    Проговорите компромиссы: память против точности, задержка против строгости синхронизации между инстансами.
  • 4
    Redis + Lua: атомарные операции убирают гонки при обновлении счётчиков.
  • 5
    Поведение при сбое: что делать, если сам лимитер недоступен?

Для дополнительной практики и сравнения реализаций полезно посмотреть System Design Primer: Rate Limiter и Cloudflare Rate Limiting Rules.

Связанные главы

  • System Design Primer (краткий обзор) - даёт базовую рамку для требований, ограничений и оценки узких мест в задачах про лимиты запросов.
  • System Design Interview - Alex Xu - содержит классический интервью-разбор лимитера запросов с акцентом на алгоритмы и архитектурные компромиссы.
  • Acing the System Design Interview - дополняет тему практическими вариантами размещения лимитера в распределённой среде.
  • API Gateway - показывает основной эксплуатационный контур, где лимиты запросов чаще всего вводят централизованно.
  • API Security Patterns - связывает лимиты запросов с более широкой защитой API: аутентификацией, борьбой со злоупотреблениями и исполнением политик доступа.
  • Стратегии кэширования - помогает выбрать подход к хранению счётчиков и кэшированию так, чтобы не раздувать дополнительную задержку.
  • Resilience Patterns - расширяет тему поведения лимитера при сбоях: когда пропускать запросы, когда блокировать и как деградировать без каскадных отказов.
  • Notification System - показывает прикладной кейс, где многоуровневые лимиты сдерживают всплески нагрузки и защищают зависимые сервисы.
  • Web Crawler - демонстрирует необходимость лимитов для вежливого и контролируемого доступа к внешним источникам.
  • Payment System - даёт контекст критичных систем, где лимиты запросов защищают дорогостоящие и чувствительные операции.

Чтобы отмечать прохождение, включи трекинг в Настройки