Компьютерные сети
Rate Limiting
Один клиент с циклом без sleep может генерировать 10,000 RPS и положить ваш сервис. Rate limiting - обязательный компонент любого production API, от защиты до монетизации.
- **Twitter/X API**: 15 requests per 15-min window для поиска. Превысил - 429 Too Many Requests до конца окна
- **Stripe API**: разные лимиты для read/write операций, burst capacity для пиков, постепенное восстановление
- **Cloudflare**: rate limiting на edge, защита origin серверов от перегрузки и DDoS
Предварительные знания
Token Bucket
**Token Bucket** - самый популярный алгоритм rate limiting. Представьте ведро с токенами: токены добавляются с фиксированной скоростью, каждый запрос забирает токен. Нет токенов - запрос отклонён.
**Burst capacity** - ключевое преимущество token bucket. Если клиент молчал минуту, он накопил токены и может сделать burst запросов. Это хорошо для real-world трафика.
AWS API Gateway, Stripe, GitHub API используют token bucket. Параметры: **capacity** (макс токенов), **refill rate** (токенов/сек). Запрос может требовать несколько токенов (тяжёлые операции дороже).
Token bucket с capacity=100 и rate=10/sec. Клиент молчал 20 секунд. Сколько запросов он может сделать мгновенно?
Leaky Bucket
**Leaky Bucket** - альтернатива, обеспечивающая **строго равномерный** выходной поток. Запросы попадают в очередь (bucket), обрабатываются с постоянной скоростью. Переполнение очереди - отказ.
**Leaky bucket используется** для network traffic shaping (QoS роутерах), когда нужен гарантированно равномерный поток. Для API rate limiting предпочитают token bucket из-за поддержки burst.
Nginx использует leaky bucket (ngx_http_limit_req_module). При burst параметре запросы ставятся в очередь вместо мгновенного отказа. `limit_req zone=api burst=20 nodelay;`
Когда leaky bucket лучше token bucket?
Sliding Window
**Fixed Window** считает запросы в фиксированных интервалах (например, по минутам). Проблема: на границе окон возможен burst в 2x лимита. **Sliding Window** решает это.
**Sliding Window Counter** - оптимальный баланс точности и памяти. Используется в Cloudflare, Redis rate limiting. Погрешность ~0.003% при равномерном трафике.
На интервью: Fixed Window проще всего реализовать (один счётчик), Sliding Window Log точнее всего (но дорого по памяти), Sliding Window Counter - production выбор для большинства случаев.
Почему sliding window counter предпочтительнее sliding window log в production?
Distributed Rate Limiting
При множестве серверов rate limit должен быть **глобальным**. Локальный счётчик на каждом сервере позволит клиенту превысить лимит в N раз (по числу серверов).
**Production выбор**: Redis с replica для HA. При Redis failure - fallback на local rate limit (лучше пропустить лишнее, чем отказать всем). Stripe, Discord используют этот подход.
Race condition: два сервера читают counter=99, оба инкрементят до 100, оба пропускают. Решение: атомарные операции Redis (INCR возвращает новое значение) или Lua скрипты для check-and-increment.
Как избежать race condition при distributed rate limiting?
Redis Rate Limiting
Redis - стандарт для distributed rate limiting благодаря атомарным операциям и скорости. Рассмотрим практические реализации разных алгоритмов.
**Lua scripts** выполняются атомарно в Redis - никаких race conditions. Передаём скрипт через EVALSHA (кешируется). Latency: ~0.1ms для Lua скрипта.
Лучшие практики: добавляйте jitter к TTL (избежать thundering herd), возвращайте клиенту заголовки X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After. При Redis failure - graceful degradation на local limits.
Rate limiting нужен только для защиты от DDoS атак
Rate limiting защищает от перегрузки (fair usage), обеспечивает предсказуемую производительность (SLA), и является инструментом монетизации (API tiers: free/pro/enterprise)
DDoS - лишь один сценарий. Rate limiting нужен даже без злоумышленников: один клиент с багом может положить сервис. API экономика построена на rate limits (Stripe: 100 req/sec free, 1000 req/sec paid).
Почему Lua скрипты предпочтительнее множественных Redis команд для rate limiting?
Итоги
- **Token Bucket**: позволяет burst, затем ограничивает - лучший выбор для API
- **Leaky Bucket**: сглаживает трафик до константы - для network shaping
- **Sliding Window Counter**: O(1) память, нет boundary burst - production стандарт
- **Redis + Lua**: атомарные операции для distributed rate limiting
Связанные темы
Rate limiting связан с другими паттернами защиты и масштабирования:
- Load Balancing — Rate limit часто на уровне load balancer
- API Gateway — Gateway - централизованное место для rate limiting
- Resilience Patterns — Rate limit + circuit breaker для полной защиты
Вопросы для размышления
- Как бы вы реализовали разные rate limits для free и premium пользователей?
- Что делать, если Redis недоступен - отказывать всем или пропускать всех?
- Как rate limiting взаимодействует с retry логикой клиента?