Rate limits и квоты
Rate limits и квоты — это фундаментальная механика управления спросом на общие ресурсы: CPU, сеть, БД, очереди, внешние API. Цель — справедливость (fairness), предсказуемость SLO и защита от всплесков, злоупотреблений и «noisy neighbor».
1) Базовые понятия
Rate limit — ограничение интенсивности запросов/операций (req/s, msg/min, байт/сек).
Burst — допустимый кратковременный всплеск поверх среднего rate.
Quota — лимит объема за окно времени (документов/сутки, ГБ/месяц).
Concurrency cap — ограничение одновременных операций (одновременных запросов/джобов).
Scope — область применения: per-tenant, per-user, per-token, per-endpoint, per-IP, per-region, per-feature.
2) Алгоритмы лимитирования
2.1 Token Bucket (ведро с токенами)
Параметры: `rate` (токенов/сек), `burst` (размер ведра).
Работает как «кредит»: накопленные токены позволяют короткие пики.
Подходит для внешних API и пользовательских запросов.
2.2 Leaky Bucket (протекающее ведро)
Плавно «стравливает» поток с постоянной скоростью.
Хорош для сглаживания трафика к чувствительным backend’ам.
2.3 Fixed/Sliding Window
Fixed window: просто, но уязвимо к «переключению окна».
Sliding window: точнее, но дороже вычислительно.
2.4 GCRA (Generic Cell Rate Algorithm)
Эквивалент Token Bucket в терминах виртуального времени прибытия.
Точен и стабилен для распределенных лимитеров (менее конфликтный state).
2.5 Concurrency Limits
Ограничение одновременно выполняемых операций.
Защищает от истощения пулов потоков/соединений и «head-of-line blocking».
3) Где применять лимиты
На границе (L7/API-шлюз): основной барьер, быстрый отказ (429/503), дешевые проверки.
Внутри сервисов: дополнительные caps на тяжелые операции (экспорты, отчеты, трансформации).
На выходе к внешним системам: индивидуальные лимиты под третьи стороны (anti-penalty).
На очередях/воркерах: fairness к общим пулам.
4) Скоупы и приоритеты (multi-tenant)
Иерархия: Global → Region → Tenant/Plan → User/Token → Endpoint/Feature → IP/Device.
Priority-aware: VIP/Enterprise получают больший `burst` и вес, но не ломают общие SLO.
Композиция лимитов: итоговый допуск = `min(глобальный, региональный, тенантный, пользовательский, эндпойнтный)`.
5) Квоты по объему
Суточные/месячные квоты: документы/сутки, ГБ/месяц, сообщения/мин.
Мягкие/жесткие пороги: предупреждения (80/90%) и «жесткий стоп».
Roll-up: учет по объектам (таблицы, файлы, события) и «снятие» в биллинг.
6) Распределенные лимитеры
Требования: низкая задержка, согласованность, устойчивость к отказам, горизонтальное масштабирование.
Local + probabilistic sync: локальные шардовые ведра + периодическая синхронизация.
Central store: Redis/KeyDB/Memcached с LUA/atomic ops (INCR/PEXPIRE).
Sharding: ключи вида `limit:{scope}:{id}:{window}` с равномерным распределением.
Clock skew: хранить «истину» на сервере лимитера, а не в клиентах.
Идемпотентность: ключи «операций» (Idempotency-Key) уменьшают ложные списания.
7) Анти-абьюз и защита
Per-IP + device fingerprint для публичных эндпойнтов.
Proof-of-Work / CAPTCHA при аномалиях.
Slowdown (throttling) вместо полного отказа, когда UX важнее (поисковые подсказки).
Adaptive limits: динамическое снижение порогов при инцидентах/дорогих деградациях.
8) Поведение клиента и протокол
Коды: `429 Too Many Requests` (rate), `403` (превышена квота/план), `503` (защитная деградация).
Заголовки ответов (best practice):- `Retry-After:
` — когда пробовать снова.
- `RateLimit-Limit:
;w= ` - `RateLimit-Remaining:
` - `RateLimit-Reset:
` - Backoff: экспоненциальный + джиттер (full jitter, equal jitter).
- Идемпотентность: заголовок `Idempotency-Key` и повторяемость безопасных операций.
- Тайм-ауты и отмена: корректно прерывать подвисшие запросы, чтобы не «захватывать» лимиты.
9) Наблюдаемость и тестирование
Теги: `tenant_id`, `plan`, `user_id`, `endpoint`, `region`, `decision` (allow/deny), `reason` (quota/rate/concurrency).
Метрики: пропускная способность, доля отказов 429/403/503, p95/p99 задержки лимитера, hit ratio кэша ключей, распределение по планам.
Логи аудита: причины блоков, топ «шумных» ключей.
Тесты: нагрузочные профили «пила/бурст/плато», хаос — отказ Redis/шарда, рассинхронизация часов.
10) Интеграция с биллингом
Usage-счетчики собираются на границе, агрегируются батчами (каждые N мин) с идемпотентностью.
Сводка по планам: перерасход → оверчардж или временное повышение плана.
Расхождения: сверка usage vs invoice; алерты на дельту.
11) Fairness внутри (очереди, воркеры)
Weighted Fair Queuing / DRR: распределение слотов между арендаторами по весу плана.
Per-tenant worker pools: жесткая изоляция VIP/шумных.
Admission control: отказ до выполнения, если квоты исчерпаны; очереди не раздуваются.
Caps на concurrency: ограничить одновременные тяжелые джобы.
12) Типовые профили планов (пример)
yaml plans:
starter:
rate: 50 # req/s burst: 100 concurrency: 20 quotas:
daily_requests: 100_000 monthly_gb_egress: 50 business:
rate: 200 burst: 400 concurrency: 100 quotas:
daily_requests: 1_000_000 monthly_gb_egress: 500 enterprise:
rate: 1000 burst: 2000 concurrency: 500 quotas:
daily_requests: 10_000_000 monthly_gb_egress: 5000
13) Архитектурный эталон (словесная схема)
1. Edge/API-шлюз: TLS → извлечь контекст (tenant/plan) → проверить лимиты/квоты → расставить заголовки RateLimit- → лог/трейс.
2. Policy Engine: правила приоритета (VIP), адаптивные пороги.
3. Limiter Store: Redis/KeyDB (atomic ops, LUA), шардирование ключей, репликация.
4. Services: вторичный лимит и caps на тяжелые операции; идемпотентность; очереди с WFQ/DRR.
5. Usage/Billing: сбор, агрегация, инвойс, алерты по порогам.
6. Observability: метрики/логи/трейсы с тегами, дашборды per-tenant.
14) Чек-лист перед продом
- Определены scопы лимитов (tenant/user/token/endpoint/IP) и их иерархия.
- Выбран алгоритм (Token Bucket/GCRA) и параметры `rate/burst`.
- Реализованы concurrency caps и admission control для тяжелых операций.
- Включены заголовки `RateLimit-` и `Retry-After`; клиенты поддерживают backoff + jitter.
- Лимитер распределенный и устойчивый к отказам (шарды, репликация, деградация).
- Usage-сбор идемпотентен; связка с биллингом, алерты на перерасход.
- Наблюдаемость: метрики/трейсы/логи с тегами, топ «шумных» ключей, alerter’ы.
- Тесты: бурсты, «пила», отказ стора, clock skew, холодный старт.
- Документация для клиентов: лимиты по планам, примеры 429/Retry-After, best practices ретраев.
- Политика исключений: как временно повышать лимиты и когда.
15) Типичные ошибки
Глобальный лимит без per-tenant/per-endpoint — «noisy neighbor» ломает всем SLO.
Отсутствие `burst`: UX страдает при коротких всплесках.
Использование только фиксированного окна → «двойной удар на границе окна».
Нет идемпотентности и ретраев с джиттером → шторм повторов.
Лимиты только на границе, без caps в сервисах/очередях → внутренние «пробки».
Неотражение лимитов в ответах (нет `Retry-After`, `RateLimit-`) → клиенты не адаптируются.
Хранение состояния лимитера в БД OLTP → высокая латентность и «горячие» блокировки.
16) Быстрый выбор стратегии
Публичные API с пиками: Token Bucket + большой `burst`, RateLimit- заголовки, CDN/edge кеш.
Внутренние тяжелые джобы: concurrency caps + WFQ/DRR, admission control.
Интеграции c третьими сторонами: отдельные лимиты на выход, буферизация/ретраи.
Мульти-тенант SaaS: иерархия лимитов (global→tenant→user→endpoint), VIP приоритизация, квоты по месяцам.
Заключение
Хорошие rate limits и квоты — это системный контракт между платформой и клиентом: честная доля ресурсов, устойчивость к всплескам, предсказуемые SLO и прозрачный биллинг. Комбинируйте алгоритмы (Token/GCRA + concurrency caps), внедряйте иерархию скопов, отдавайте понятные заголовки и метрики, и регулярно проверяйте схемы под реальными профилями трафика — так платформа останется устойчивой даже при агрессивном росте нагрузки.