VK Object Storage logo
Помощь
Обновлена 20 октября 2026 г. в 12:40

Ограничение потока запросов (Rate Limiting)

Особенности ограничения потока запросов

  • Лимитирование выполняется на балансировщике нагрузки (NGINX) — это исключает двойное лимитирование одного запроса.
  • При достижении лимита ресурса балансировщик возвращает 503 с телом SlowDown.
  • Поддерживаются лимиты на уровне ресурса, префикса и метода (подробнее — в разделе Уровни лимитов).
  • Конфигурация лимитов хранится в etcd и применяется без перезапуска компонентов (подробнее — в разделе Квоты).

Поток обработки запроса

Схема потока обработки запроса приведена на рисунке 1.

Схема потока обработки запроса
Рисунок 1 — Схема потока обработки запроса

Порядок обработки:

  1. Пользователь отправляет S3-запрос к бакету или объекту на балансировщик NGINX.

  2. В NGINX срабатывает access_by_lua_block — вызов require("rate").attempt(".levee", {...}), запрос перенаправляется во внутренний location .levee и через proxy_pass попадает на levee-client (client-proxy).

  3. levee-client отправляет запрос к observer для получения списка активных limiter.

  4. levee-client получает от observer список активных limiter.

  5. По ключу ресурса алгоритм HRW (Rendezvous Hashing) выбирает группу limiter.

  6. В рамках группы запрос маршрутизируется на конкретный limiter по выбранному внутри группы методу round-robin.

  7. limiter ищет квоту по переданному ресурсу, префиксу и методу, затем нормализует найденную квоту по размеру группы и проверяет алгоритмом GCRA.

  8. limiter возвращает результат:

    • 200 (accepted) — доступ разрешен;
    • 429 (rejected) — лимит исчерпан;
    • 500 (failed) — внутренняя ошибка.
  9. levee-client передает результат в NGINX.

    • accepted — запрос продолжает обработку в S3;
    • rejected — запрос отклонен.
  10. NGINX возвращает пользователю ответ от S3 или 503 с телом SlowDown.

Логирование

Все компоненты Levee передают логи непосредственно в syslog. Для разбора решений Levee по конкретному запросу используйте следующие данные:

  • NGINX — в access_log выводится только значение переменной с результатом работы limiter (accepted, rejected, failed);
  • client-proxy (levee-client) — результат и адрес limiter, выдавшего решение;
  • limiter (levee-limiter) — решения по каждому запросу.

Общие принципы логирования Системы описаны отдельно (подробнее — в разделе Логирование).

Установка лимитов

Чтобы изменить лимиты ресурса:

  1. Выясните желаемый RPS и burst. Burst позволяет превысить лимит на короткий период — запросы приходят неравномерно.
  2. Добавьте 10% к желаемому RPS.
  3. Если burst неизвестен, вычислите его по формуле (подробнее — в разделе Расчет квоты).
  4. Определите уровень лимита: ресурс целиком, конкретный метод или префикс.

Расчет квоты

Лимиты задаются парой (rate, burst):

  • rate — максимальная интенсивность, запросов в секунду;
  • burst — допустимая пульсация, запросов.

Формулы:

rate=RPS×1,1 rate = \text{RPS} \times 1{,}1 burst=rateDF×0,1 burst = \frac{rate}{\text{DF}} \times 0{,}1

Здесь:

  • RPS — желаемое пользователем количество запросов в секунду (Requests Per Second);
  • DF — размер группы limiter.

Размер группы limiter — значение factor в конфигурации Levee в etcd (подробнее — в разделе Размер группы limiter).

Пример: rate = 1000, DF = 4 →

burst=10004×0,1=25 burst = \frac{1000}{4} \times 0{,}1 = 25

Уровни лимитов

Лимиты устанавливаются на нескольких уровнях. Ниже — примеры в формате YAML из конфигурации etcd.

default

Общие лимиты для всех ресурсов:

default:    rate: 1000    burst: 500methods_default:    ListObjects:        rate: 250        burst: 250

resource

Лимиты для конкретного ресурса (бакета):

example-bucket:    quota:                 # стандартная квота для всех обращений к ресурсу; используется при отсутствии совпадений на уровне ниже        rate: 2000        burst: 250    prefixes:        - prefix: "photos/2024"    # все запросы к объектам внутри префикса — одна квота          quota:              rate: 1700              burst: 300        - prefix: "uploads/*"      # wildcard — на каждый объект внутри префикса своя квота          quota:              rate: 1700              burst: 300        - prefix: ""                # квота на весь ресурс; можно задать квоты на конкретные методы          quota:              rate: 1700              burst: 300          methods:              PutObject:            # квота на конкретный метод                  rate: 100                  burst: 25

Поиск клиентов, превысивших лимит

Клиент, превысивший лимит, получает от Levee код 429, а на уровне NGINX это отражается ответом 503.

Для поиска используйте штатные средства, доступные в инсталляции: логи компонентов на серверах, логи роли Logs или подключенная внешняя система, например ELK.

Пример поиска ответов 503 в access-логах NGINX:

$ grep ' 503 ' <ЛОГ-ФАЙЛ_NGINX>

Пример поиска решений по конкретному ресурсу в логах limiter:

$ grep '<РЕСУРС>' <ЛОГ-ФАЙЛ_LIMITER>

Здесь:

  • <ЛОГ-ФАЙЛ_NGINX> — путь к access-логу NGINX;
  • <РЕСУРС> — ключ ресурса;
  • <ЛОГ-ФАЙЛ_LIMITER> — путь к логу компонента limiter.

Увеличение лимитов

Рекомендации при увеличении лимитов:

  • для методов GET или PUT — увеличивайте лимит в 2–3 раза относительно текущей нагрузки;
  • для ListObjects — увеличивайте лимит только при обоснованной необходимости.

Чтобы изменить лимит, обновите соответствующее значение квоты в etcd в порядке, принятом для внесения изменений конфигурации в вашей инсталляции (подробнее — в разделе Квоты). Levee применяет изменения без перезапуска компонентов.

Была ли статья полезна?