Ограничение потока запросов (Rate Limiting)
- Лимитирование выполняется на балансировщике нагрузки (NGINX) — это исключает двойное лимитирование одного запроса.
- При достижении лимита ресурса балансировщик возвращает
503с теломSlowDown. - Поддерживаются лимиты на уровне ресурса, префикса и метода (подробнее — в разделе Уровни лимитов).
- Конфигурация лимитов хранится в etcd и применяется без перезапуска компонентов (подробнее — в разделе Квоты).
Схема потока обработки запроса приведена на рисунке 1.
Порядок обработки:
-
Пользователь отправляет S3-запрос к бакету или объекту на балансировщик NGINX.
-
В NGINX срабатывает
access_by_lua_block— вызовrequire("rate").attempt(".levee", {...}), запрос перенаправляется во внутренний location.leveeи черезproxy_passпопадает наlevee-client(client-proxy). -
levee-clientотправляет запрос кobserverдля получения списка активныхlimiter. -
levee-clientполучает отobserverсписок активныхlimiter. -
По ключу ресурса алгоритм HRW (Rendezvous Hashing) выбирает группу
limiter. -
В рамках группы запрос маршрутизируется на конкретный
limiterпо выбранному внутри группы методу round-robin. -
limiterищет квоту по переданному ресурсу, префиксу и методу, затем нормализует найденную квоту по размеру группы и проверяет алгоритмом GCRA. -
limiterвозвращает результат:200(accepted) — доступ разрешен;429(rejected) — лимит исчерпан;500(failed) — внутренняя ошибка.
-
levee-clientпередает результат в NGINX.accepted— запрос продолжает обработку в S3;rejected— запрос отклонен.
-
NGINX возвращает пользователю ответ от S3 или
503с теломSlowDown.
Все компоненты Levee передают логи непосредственно в syslog. Для разбора решений Levee по конкретному запросу используйте следующие данные:
NGINX— в access_log выводится только значение переменной с результатом работыlimiter(accepted,rejected,failed);client-proxy(levee-client) — результат и адресlimiter, выдавшего решение;limiter(levee-limiter) — решения по каждому запросу.
Общие принципы логирования Системы описаны отдельно (подробнее — в разделе Логирование).
Чтобы изменить лимиты ресурса:
- Выясните желаемый RPS и burst. Burst позволяет превысить лимит на короткий период — запросы приходят неравномерно.
- Добавьте 10% к желаемому RPS.
- Если burst неизвестен, вычислите его по формуле (подробнее — в разделе Расчет квоты).
- Определите уровень лимита: ресурс целиком, конкретный метод или префикс.
Лимиты задаются парой (rate, burst):
rate— максимальная интенсивность, запросов в секунду;burst— допустимая пульсация, запросов.
Формулы:
Здесь:
RPS— желаемое пользователем количество запросов в секунду (Requests Per Second);DF— размер группыlimiter.
Размер группы limiter — значение factor в конфигурации Levee в etcd (подробнее — в разделе Размер группы limiter).
Пример: rate = 1000, DF = 4 →
Лимиты устанавливаются на нескольких уровнях. Ниже — примеры в формате YAML из конфигурации etcd.
Общие лимиты для всех ресурсов:
default:rate: 1000burst: 500methods_default:ListObjects:rate: 250burst: 250
Лимиты для конкретного ресурса (бакета):
example-bucket:quota: # стандартная квота для всех обращений к ресурсу; используется при отсутствии совпадений на уровне нижеrate: 2000burst: 250prefixes:- prefix: "photos/2024" # все запросы к объектам внутри префикса — одна квотаquota:rate: 1700burst: 300- prefix: "uploads/*" # wildcard — на каждый объект внутри префикса своя квотаquota:rate: 1700burst: 300- prefix: "" # квота на весь ресурс; можно задать квоты на конкретные методыquota:rate: 1700burst: 300methods:PutObject: # квота на конкретный методrate: 100burst: 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 применяет изменения без перезапуска компонентов.