Что такое 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 и понятная обратная связь для клиентов) защищает систему и улучшает пользовательский опыт при пиковых нагрузках.