Rate limiting: защита от перегрузки
Как ограничить число запросов от клиента и защитить систему от злоупотреблений и пиков.
Rate limiting — ограничение числа запросов от клиента за интервал времени, чтобы защитить систему от перегрузки, abuse и каскадных отказов.
Зачем
Без лимитов один агрессивный клиент (бот, цикл с багом, атака) способен исчерпать ресурсы и уронить сервис для всех. Rate limiting вводит честные квоты: например, 100 запросов в минуту на пользователя, лишние получают ответ 429 Too Many Requests.
Основные алгоритмы
| Алгоритм | Идея |
| Token bucket | Бакет токенов пополняется со временем; запрос тратит токен |
| Leaky bucket | Запросы вытекают с постоянной скоростью, очередь сглаживает |
| Fixed window | N запросов на фикс. окно; просто, но всплеск на границе |
| Sliding window | Скользящее окно; точнее, чуть дороже |
Token bucket — частый дефолт: допускает короткие всплески (накопленные токены), но держит среднюю скорость.
Где ставить
Лимитер обычно живёт на границе — в API Gateway или перед приложением. Решение «пропустить/отклонить» должно быть очень быстрым, чтобы не стать само узким местом.
Клиент -> [Rate limiter] --разрешено--> App
|--превышено--> 429 Too Many RequestsКак работает под капотом
В горизонтально масштабированной системе лимитер должен быть распределённым: счётчики хранят в общем Redis, иначе на каждом инстансе будет свой счётчик и реальный лимит умножится на число инстансов. Атомарность инкремента (INCR + EXPIRE) гарантирует корректный учёт. В ответе полезно отдавать заголовки X-RateLimit-Remaining и Retry-After, чтобы клиент знал квоту.
Частые ошибки
- Хранить счётчики локально на инстансах -> лимит «размножается».
- Сделать лимитер тяжёлым и превратить его в узкое место.
- Не отдавать клиенту заголовки с остатком квоты и Retry-After.
Итог
- Rate limiting защищает от перегрузки и злоупотреблений, отдавая 429.
- Token bucket — удобный дефолт: всплески + средняя скорость.
- В масштабе лимитер распределённый (Redis), счётчики общие и атомарные.