← Back to blog

L7 Security: Rate Limiting

⚙️ Теория

🎯 Зачем нужен rate limiting

Rate limiting решает минимум три задачи:

  • защита от brute force;
  • ограничение API abuse;
  • смягчение L7 flood.

Важно: это не только security-инструмент, но и механизм контроля стоимости ресурса origin.


🧮 Алгоритмы

Token Bucket

  • В «ведре» есть токены.
  • Запрос расходует токен.
  • Токены пополняются с заданной скоростью.
  • Есть controlled burst за счёт накопленных токенов.

Хорошо подходит для API, где нужна эластичность на коротких пиках.

Leaky Bucket

  • Входящие запросы выравниваются к фиксированной скорости «утечки».
  • Избыточные заявки задерживаются или отбрасываются.

В NGINX limit_req описан как leaky bucket.

Fixed Window

  • Счётчик запросов в фиксированном интервале (N req / 1m).
  • Просто и дёшево.
  • Минус: boundary burst на границе окон.

Sliding Window

  • Учитывает текущее окно + часть предыдущего.
  • Меньше boundary-артефактов, чем fixed window.
  • Дороже по вычислению/состоянию.

Sliding Log

  • Хранит timestamp каждого события в скользящем интервале.
  • Самая точная модель лимита.
  • Самая дорогая по памяти/операциям.

🌐 Distributed Rate Limiting

Проблемы распределённого лимитера:

  • race conditions при конкурентных обновлениях;
  • consistency между узлами;
  • replication lag (особенно при async replication);
  • hot keys и неравномерная нагрузка.

Рабочие паттерны:

  • sharded counters;
  • consistent hashing по limit key;
  • local + global hybrid (локальный токен-бакет + глобальный decision service).

🛠️ Ключевые параметры

  • limit key: IP / user / API token / route + token.
  • burst: сколько допускаем кратковременно сверх steady rate.
  • delay vs drop: деградировать мягко или жёстко отбрасывать.
  • sliding granularity: точность окна vs стоимость вычисления.

Что нужно уметь объяснить

Почему distributed rate limiting сложнее локального?

Локальный лимитер видит только локальный поток.
Distributed лимитер должен синхронно (или квазисинхронно) согласовать состояние между узлами под гонками и задержками репликации.

Почему ключ лимита важнее «самого алгоритма»?

Плохой key (IP за NAT, общий service token) даёт или массовые FP, или бесполезно слабую защиту.

Когда лучше delay, а когда drop?

  • delay: когда важно мягко сгладить всплеск.
  • drop/429: когда нужно быстро освободить ресурсы origin.

🧪 Практика

1. Базовый лимит в NGINX

limit_req_zone $binary_remote_addr zone=api_limit:20m rate=20r/s;

location /api/ {
    limit_req zone=api_limit burst=40 nodelay;
    proxy_pass http://backend;
}

2. Проверьте поведение на burst

wrk -t8 -c400 -d30s https://example.com/api/

Смотрите:

  • долю 429/503;
  • latency p95/p99;
  • CPU на edge/origin.

3. Разделите ключи лимита

Сравните:

  • только IP;
  • API token;
  • composite key (route + token).

4. Для distributed-модели разделите local/global слой

  • local limiter на edge (быстрый fail-fast);
  • global limiter для account-wide quota/policy.

🧾 Вывод

Rate limiting это задача про математику + распределённые системы.
Надёжная защита достигается не выбором «модного» алгоритма, а правильной комбинацией key, burst, local/global архитектуры и измерением side-effects на latency/FP.


📚 Ссылки


Проверка источников

L7 Security: Rate Limiting | Aleksandr Suprun