Что такое rate limiting и зачем он нужен?

Rate limiting — механизм ограничения скорости запросов к сервису: сколько операций (запросов, сообщений, транзакций) разрешено выполнять за единицу времени для конкретного субъекта (пользователь, IP, API-ключ) или глобально. Цель — защитить систему от перегрузки, предотвратить DoS/DDoS, обеспечить справедливое распределение ресурсов и реализовать тарифные/квотные политики.

Зачем нужен rate limiting

  • предотвращает исчерпание ресурсов (CPU, память, соединения, БД);

  • защищает внешние зависимости от лавинообразной нагрузки;

  • реализует бизнес-правила (платные уровни, fair use);

  • снижает риск cascade failure при проблемах;

  • контролирует спам и автоматические атаки.

Основные алгоритмы

  • Fixed window (counting) — считать запросы в фиксированном окне (например, 1000 запросов/час). Простой, но подвержен краю окна (bursting на границе).

  • Sliding window (log/rolling) — точнее отслеживает последние N секунд (хранит временные метки или реализует сглаживание).

  • Token bucket — система с токенами, генерируемыми с постоянной скоростью; каждый запрос «съедает» токен. Позволяет бустить (burst) — накопленные токены дают временные пики. Очень популярна.

  • Leaky bucket — очередь с фиксированным выходным потоком; сглаживает входящие пики, подходит для равномерной обработки.

Granularity (на каких ключах ограничивать)

  • per-user (user_id) — часто для API клиентов;

  • per-API key / per-app — для партнёров;

  • per-IP — для защиты от анонимных атак;

  • per-endpoint / per-method — разные лимиты для тяжёлых операций;

  • global — общий потолок для сервиса.

Где реализуют

  • edge / CDN (Cloudflare, Fastly) — early blocking;

  • API Gateway / load balancer (AWS API Gateway, ALB, Kong, Envoy) — централизованная логика;

  • service mesh (Envoy) — распределённый enforcement в кластере;

  • на самом приложении (local token bucket) — простота и гибкость;

  • в Redis/DB (централизованно) — для распределённого контроля и консистентности (Lua-скрипты для атомарности).

Распределённые паттерны

  • Central store (Redis) с атомарными Lua-скриптами — точные счётчики;

  • Local token bucket + sync — быстрое локальное решение с периодической синхронизацией в центральный стор (уменьшает задержки);

  • Consistent hashing для распределения ключей по нескольким rate servers;

  • Hierarchical limits — сначала edge/global, затем per-user на бэкенде.

Ответ клиенту и заголовки

  • при превышении — код 429 Too Many Requests.

  • рекомендованные заголовки:
    X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (unix timestamp) и/или Retry-After.

  • указывайте понятный Retry-After и политику backoff (exponential backoff) на клиентской стороне.

Quotas vs Rate Limits

  • Rate limit — скорость (requests/sec).

  • Quota — накопляемое ограничение (например, 1M calls/month). Часто комбинируют: скорость + месячная квота.

Мониторинг и метрики

  • число отклонённых запросов (429), процент throttled;

  • latency и error rate для throttled клиентов;

  • топ-ключи по числу отклонений;

  • эффект на downstream (снижение нагрузки).

Лучшие практики

  • позволять небольшие bursts (token bucket) для UX;

  • предоставлять клиентам прозрачность через заголовки и docs;

  • дифференцировать лимиты по тарифам;

  • применять rate limiting как первый слой защиты (edge) и второй — в сервисе;

  • тестировать сценарии пиков/атак;

  • учитывать clock skew (синхронизация времени) в распределённых реализациях;

  • избегать высокой кардинальности ключей (перенасыщение хранилища счётчиков).

Типичные проблемы и решения

  • Race conditions — использовать атомарные операции (Redis Lua).

  • SPOF при центральном сторе — сделать HA/кластер Redis и fallback локальных лимитов.

  • High cardinality — аггрегировать по группам, использовать probabilistic counters или TTL для ключей.

Rate limiting — ключевой компонент устойчивости и безопасности сервиса: грамотная стратегия (алгоритм, границы, точки Enforcement и понятная обратная связь для клиентов) защищает систему и улучшает пользовательский опыт при пиковых нагрузках.