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.
Інтеграції з третіми сторонами: окремі ліміти на вихід, буферизація/ретраї.
Мульти-тенант SaaS: ієрархія лімітів (global→tenant→user→endpoint), VIP пріоритизація, квоти по місяцях.
Висновок
Хороші rate limits і квоти - це системний контракт між платформою і клієнтом: чесна частка ресурсів, стійкість до сплесків, передбачувані SLO і прозорий білінг. Комбінуйте алгоритми (Token/GCRA + concurrency caps), впроваджуйте ієрархію скопів, віддавайте зрозумілі заголовки і метрики, і регулярно перевіряйте схеми під реальними профілями трафіку - так платформа залишиться стійкою навіть при агресивному зростанні навантаження.