GH GambleHub

Проектування rate limiter'ів

1) Навіщо rate limiting

Rate limiting захищає доступність та економіку API: зупиняє флуди, «бурсти» ретраїв, credential stuffing, захищає дорогі операції (грошові транзакції, генерацію звітів), згладжує навантаження на залежні системи (БД/провайдери). Хороший дизайн дає справедливість (fairness), передбачуваність латентності і чіткі SLO.

Ключові цілі

Стабільність RPS і захист бекенду від перевантаження.
Керована «еластичність» (burst allowance).
Диференціація клієнтів (пер-користувач/пер-організація/пер-ключ/пер-IP/пер-регіон).
Вартісна модель: різні «ціни» для різних операцій.

2) Типи лімітів

RPS-ліміти: запитів за секунду/хвилину.
Квоти: сумарний бюджет у період (день/місяць).
Конкурентність: одночасні операції (checkout, heavy job).
Швидкість/смуга: байт/сек (завантаження/вивантаження).
Зважені ліміти: «вартість» запиту по складності (наприклад, GraphQL complexity, розмір batch).
Адаптивні: посилюються при аномаліях (підозріла активність/помилки 401/403/5xx).

3) Алгоритми і коли їх застосовувати

3. 1 Fixed window counter

Просто: лічильник на інтервал (наприклад, 100 r/min).
Плюси: Мінімальна вартість. Мінуси: «крайові берсти» на межах вікна.

Коли: панелі адмінок, невисока точність, низька вартість.

3. 2 Sliding window (log / counter)

Log: зберігає мітки часу останніх запитів, точний, доріг по пам'яті.
Counter: середнє двох сусідніх вікон (rolling), компроміс точності і ціни.

Коли: публічні API середнього трафіку, потрібна плавність без складної математики.

3. 3 Token bucket

Параметри: швидкість'r'( токенів/сек) і ємність'b'( burst). Кожен запит «спалює» токен.
Плюси: природний burst allowance, проста реалізація. Мінуси: немає суворої рівномірності.

Коли: майже завжди для RPS, якщо потрібні «залпи» в межах'b'.

3. 4 Leaky bucket (drip)

Черга, з якої «витікає» з фіксованою швидкістю.
Плюси: рівний вихідний потік. Мінуси: більше затримок.

Коли: згладжування до зовнішніх «крихких» провайдерів.

3. 5 GCRA (Generalized Cell Rate Algorithm)

Модель теоретичного часу прибуття (TAT):
  • 'TAT _ next = max (TAT_current, now) + 1/r', запит прийнятий, якщо'now <= TAT_current + burst/r'.
  • Плюси: строга, точна, мало пам'яті (за ключем зберігаємо TAT). Мінуси: складніше для розуміння.

Коли: потрібен строгий контроль і плавність, розподілені ліміти.

3. 6 Конкурентні семафори

Лічильник активних операцій; вхід - якщо «квитки» є; вихід - звільнення.
Коли: long-running операції, потоки, WebSocket, завантаження.

4) Модель ключів лімітів

Ключ = комбінація атрибутів:
  • `client_id`/`api_key`/`user_id`/`org_id`
  • 'IP/ASN/гео'( грубий захист)
  • 'endpoint/method'( гарячі маршрути)
  • 'scope/plan/tier'( монетизація)
  • 'idempotency _ key'( write-операції)
  • Використовуйте ієрархію: спочатку строгі пер-ключ, потім пер-організація, потім глобальні.

5) Вага запиту (cost model)

Визначайте «вартість»'cost (q)':
  • GraphQL: складність по полях × глибина.
  • REST: розмір відповіді/запиту, тип операції (read = 1, write = 3, звіт = 10).
  • Batch: `cost = min(n, cap)`.
  • Лімітуємо токени, а не «запити»: `budget -= cost(q)`.

6) Розподілена реалізація

6. 1 Сховища

In-process: ультра-швидко, але не загальний ліміт (годиться для локальних «м'яких» лімітів).
Redis: де-факто стандарт. INCR/EXPIRE, Lua-скрипти (атомарність), ZSET для sliding window, ключі з TTL.
Envoy/NGINX/Kong/Traefik: вбудовані фільтри; зручно для периметра.
Service Mesh: локальні ліміти на sidecar + глобальна синхронізація.

6. 2 Атомарність і гонки

Lua в Redis: перевірка та інкремент в одному кроці.
GCRA: зберігати один TAT з CAS/скриптом.
Узгодженість годин: NTP, монотонні таймери.
Sharding: консистентний хеш по ключу; уникайте «гарячих» шардів.

6. 3 Георозподіл

Локальні ліміти на регіональних кластерах + верхній глобальний (coarse).
CRDT/реплікація - обережно (затримки, подвійна витрата). Переважно регіональні ліміти з запасом.

7) Політики і пріоритизація

Плани: Free/Pro/Enterprise з різними'r','b', квотами.
Пріоритети: «дорогі» маршрути отримують менший ліміт або більший cost.
Списки: allow-list для інтеграцій, deny по ASN/проксі/ТОR.
Ескалація: при повторному перевищенні - знижуємо ліміт, вводимо proof-of-work/капчу/челенджі.

8) Приклади конфігів

8. 1 Envoy (HTTP rate limit filter, псевдо)

yaml rate_limit:
domain: public-api descriptors:
- key: api_key rate_limit:
unit: second requests_per_unit: 50 burst: 100
- key: api_key value: payments. write rate_limit:
unit: second requests_per_unit: 5 burst: 10

8. 2 NGINX (lua + Redis, псевдо)

nginx lua_shared_dict limits 10m;

location /api/ {
access_by_lua_block {
local key = ngx. var. arg_apikey.. ":".. ngx. var. request_method.. ":".. ngx. var. uri
-- token bucket in Redis (evalsha)
local allowed, retry_after = ratelimit_allow(key, 50, 100) -- r=50/s, b=100 if not allowed then ngx. header["Retry-After"] = retry_after return ngx. exit(429)
end
}
proxy_pass http://backend;
}

8. 3 Конкурентні ліміти (псевдокод)

pseudo on_request_start(key):
if redis. incr_with_ttl("sem:" + key, ttl=60) > MAX_CONCURRENCY:
redis. decr("sem:" + key); reject(429)
on_request_finish(key):
redis. decr("sem:" + key)

8. 4 GCRA (псевдокод)

pseudo params: r tokens/sec, burst b tat = redis. get(key) or now allowed_time = tat - (b / r)
if now < allowed_time: reject(429, retry_after = allowed_time - now)
tat_next = max(tat, now) + 1/r redis. set(key, tat_next, ttl = ceil(b/r) + safety)

9) Інтеграція з ретраями, таймаутами і circuit breaker

Retry-budget: обмежте частку ретраїв до X% від основного трафіку.
Jitter: при backoff завжди додавайте джиттер - зменшує синхронні сплески.
Circuit breaker: при високій помилковості ('5xx', timeouts) знижуйте ліміти або переводьте частину маршрутів в «read-only».
Hedging: акуратно; враховуйте cost, щоб не подвоювати витрати бюджету.

10) Спостережуваність і управління

Метрики: `rps_allowed`, `rps_blocked`, `429_rate`, `retry_after_avg`, `burst_used`, `quota_remaining`, `active_concurrency`.
Лейбли: за ключем ліміту, регіоном, ендпоінтом, планом.
Логи рішень (семпльовані): причина відмови, поточні лічильники, TTL ключа.
Дашборди: теплові карти за ключами/ендпоінтами, «гарячі» клієнти.
Алерти: зростання 429> 2-5% на критичних маршрутах, часті «вичерпання» квот, дисбаланс шардів.

11) Тестування та валідація

Контрактні тести політик (таблиці «якщо-то»).
Навантажувальні: бурсти (x10 від r), тривалі плато, «брудні» патерни (slow-POST, довгі з'єднання).
Chaos-трафік: нерівномірні потоки, clock drift, випадання Redis/mesh.
А/В-включення: canary rollout лімітів, shadow-рішення (логуємо, але не блокуємо) перед включенням.

12) Edge-кейси і тонкощі

Clock skew: використовуйте'now ()'з єдиного джерела (сервер), а не з заголовків клієнта.
Idempotency-Key: для write - знижує amplification при ретраях.
Batch-операції: лімітуйте за розміром батча і за сумарним cost.
Long-poll/WebSocket: лімітуйте за кількістю каналів/підписок і за тривалістю.
Cold start: «теплий» старт лічильників/передзавантаження; інакше сплески помилкових 429.
Обчислювально дорогі запити: лімітуйте до виконання бізнес-логіки.
Межі TTL: TTL ключів повинен покривати вікно + запас (safety margin).

13) Антибот-ескалації

Сходинки: попередження → 429 +'Retry-After'→ чаллендж (капча/пазл) → тимчасовий блок.
Сигнали: device-fingerprint, поведінка курсору/таймінги, TOR/проксі/хостинги.
Політики повинні бути детерміновані і відтворювані для форензики.

14) Безпека та комплаєнс

Deny-by-default на критичних маршрутах (write/фінанси).
Аудит: зберігайте рішення щодо лімітів для регуляторних кейсів і розборів інцидентів.
PII: ключі лімітів не повинні розкривати персональні дані в логах.

15) Чек-лист prod-готовності

  • Визначено ключі лімітів і cost-модель.
  • Обраний алгоритм (token bucket/GCRA) і сховище (Redis/шлюз).
  • Політики для tier'ів клієнтів + глобальні «запобіжники».
  • Конкурентні ліміти для довгих операцій.
  • Retry-budget, backoff з джиттером, інтеграція з circuit breaker.
  • Дашборди/алерти, семпльовані логи рішень.
  • Canary-включення і shadow-режим.
  • Тести бурстів, тривалих плато, збоїв Redis, clock skew.
  • Документація для клієнтів: коди 429,'Retry-After', приклади експоненціального backoff.

16) TL; DR

Використовуйте token bucket або GCRA з Redis/шлюзом, проектуйте ключі лімітів і вартість запитів, додавайте конкурентні семафори для довгих операцій, інтегруйте з retry-budget і circuit breaker, спостерігайте за 429 і «бурст-ємністю», розкочуйте ліміти через canary/shadow і обов'язково тестуйте бурсти і відмову сховища.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.