Token bucket дозирует среднюю скорость и разрешает короткий всплеск до ёмкости ведра. Лимит на gateway режет дёшево по IP или ключу. В приложении — по пользователю после auth. Без общего счётчика N реплик дают N-кратную квоту.
Авторизация и устойчивость HTTP http собеседование
Без лимита один клиент (или бот) съедает пул БД, воркеры и соседей по кластеру. Rate limit — справедливость и защита ёмкости, не «безопасность» в смысле криптографии. Честному клиенту отвечают 429 и желательно Retry-After, а не молчаливым таймаутом каскадом.
Алгоритмов несколько. Fixed window прост и даёт всплеск на границе окна. Sliding window ровнее и дороже по состоянию. Leaky bucket сглаживает жёстче. Token bucket объясняют чаще всего: ведро жетонов хорошо рисуется.
Token bucket
Token bucket простыми словами: ведро с жетонами. Каждый запрос берёт жетон. Жетоны капают с постоянной скоростью. Если ведро пустое — 429. Если ведро полное — можно пачкой запросов сразу. Это всплеск.
Ёмкость ведра — B. Скорость капели — R. Запрос стоит один жетон. Или вес: тяжёлый export стоит больше. Средняя скорость не выше R. Это не «ровно N каждые 60 секунд без всплесков» и не бесконечный трафик «потому что есть JWT».
Пример. Ведро на 20 жетонов, капает 5 в секунду. Можно сразу стукнуть 20 запросов. Потом — не быстрее 5 в секунду. Короткий всплеск разрешён, средняя скорость ограничена.
// tokens = min(B, tokens + R*dt)
// if tokens >= cost { tokens -= cost; allow } else { 429 }
//
// B=20, R=5/s → короткие 20 запросов подряд, затем ~5 rps
//
// gateway: лимит по IP / API-key, дёшево, до auth
// app: лимит по user_id после JWT, разные квоты на POST /export
//
// 3 реплики × 100 rps локально ≈ 300 rps суммарно без Redis
// лучше 429, чем таймаут пула БД
Ведро: всплеск до ёмкости, refill задаёт среднюю скорость. Общий счётчик нужен, если реплик несколько.
Где ставить
Ключ лимита важнее формулы. IP за NAT — общая квота на офис. API-ключ и user id точнее, но появляются после auth: CPU на TLS и парсинг уже потрачены. Поэтому грубый край и тонкий слой внутри часто живут вместе.
- API gateway, ingress, CDN — рано и дёшево, по IP или ключу. Не знают «этот user — VIP», пока нет заголовка.
- В приложении — после auth, квоты по ручкам. Поздно: парсинг и TLS уже были.
- Оба слоя: грубый на краю, тонкий внутри.
В нескольких репликах локальный счётчик в памяти даёт суммарную квоту ≈ лимит × число подов. Нужен Redis (или аналог) либо доля квоты на под с запасом. 429 предсказуемее, чем исчерпанный пул и 502 у соседей.
Пример. Три пода, на каждом «100 rps». Без общего счётчика это 300 rps на БД. БД не выдержит. Клиенты увидят таймауты, не честный 429.
Типичная ошибка
Лимитировать только по IP и удивиться, что мобильный оператор сидит на одном адресе. Или поставить лимит в каждом поде «по 100 rps» без общего состояния и получить кратный запас, который БД не выдержит.
На собеседовании
Нарисуйте token bucket: ёмкость, refill, всплеск. Спросите ключ (IP ломается NAT) и согласованность между репликами. Край режет дёшево по IP/ключу; приложение — по пользователю после auth.