Назад к блогу

Голого RPS недостаточно: сравниваем API Gateway в реальном сценарии

Голого RPS недостаточно: сравниваем API Gateway в реальном сценарии

api-gateway · сравнение с рынком

Nginx быстрее api-gateway в базовом замере на 12%. Это единственная цифра, которую обычно показывают в таких сравнениях, — и она почти ничего не говорит о продакшене. Как только гейтвею поручают реальную работу, порядок меняется: встроенная проверка JWT стоит api-gateway 15% пропускной способности, а вынесенный auth-сервис, к которому приходится прибегать Nginx, — 89%. Разница в разы возникает не из-за качества продукта, а из-за архитектуры: проверять токен на месте или ходить за ответом по сети на каждый запрос.

Сравнение с: Traefik v3.1 · Nginx 1.27 · Envoy v1.31 · Kong 3.7 Методология: одинаковый бэкенд, 2 vCPU / 768 MB на гейтвей, wrk, 300 соединений

Почему голый RPS вводит в заблуждение

Бенчмарк «голого» прокси прост: один бэкенд, одинаковое железо, дефолтные настройки, максимальный RPS. Он честно отвечает на вопрос «сколько запросов в секунду выдержит прокси, пока он только маршрутизирует запросы», — но этот вопрос не совпадает с тем, что происходит в проде. В продакшене гейтвей проверяет токены, применяет роли и права, пишет аудит и сам находит сервисы. Каждая из этих обязанностей добавляет работу на горячем пути, и именно она определяет, сколько трафика выдержит система и сколько компонентов придётся эксплуатировать.

Мы взяли пять гейтвеев — api-gateway, Traefik, Nginx, Envoy и Kong — поставили на одинаковое железо и добавляли обязанности по одной, замеряя, чего каждая стоит. Ниже — четыре шага от голого прокси к продакшен-гейтвею. Это те же замеры, что и в полном сравнении, но выстроенные как один аргумент: от базовой скорости к авторизации, правам, аудиту и discovery.

Шаг 1. Проверяем базовую скорость

Начинаем с точки отсчёта — тот самый голый RPS. На 300 соединениях api-gateway выдаёт 24 068 запросов в секунду, Nginx — 27 216, а Traefik, Envoy и Kong держатся в диапазоне 24 811–25 322. Все пять — в одном классе, и разрыв api-gateway с лидером составляет 12%.

Пропускная способность по гейтвеямзапросов / секунду
api-gatewayостальные четыресветлее = 50 соединений · насыщенно = 300
010k20k30kapi-gateway · 50 соединений · 25 493 запр/сapi-gateway · 300 соединений · 24 068 запр/сapi-gateway24 068/сTraefik · 50 соединений · 24 092 запр/сTraefik · 300 соединений · 24 811 запр/сTraefik24 811/сNginx · 50 соединений · 27 135 запр/сNginx · 300 соединений · 27 216 запр/сNginx27 216/сEnvoy · 50 соединений · 24 847 запр/сEnvoy · 300 соединений · 25 272 запр/сEnvoy25 272/сKong · 50 соединений · 24 988 запр/сKong · 300 соединений · 25 322 запр/сKong25 322/с
Одинаковый бэкенд, равный бюджет CPU/памяти; дефолтные настройки, без плагинов и ускорителей.

На 50 соединениях отставание даже меньше — 25 493 против 27 135 у Nginx, — так что 12% — это верхняя граница разрыва, а не величина, которая растёт под нагрузкой.

Память в этом сценарии тоже в пределах ожидаемого. Пиковая резидентная память при 300 соединениях из общего потолка 768 MB: Nginx — 15.8 MB, Envoy — 29.1 MB, api-gateway — 121.5 MB, Traefik — 174.8 MB, Kong — 314.1 MB. api-gateway тяжелее лёгких Nginx и Envoy, но заметно легче Traefik и Kong. Вывод шага: по базовой скорости все пять — один класс, а 12% — это цена, которую стоит помнить, но не та, из-за которой выбирают архитектуру.

Шаг 2. Включаем авторизацию

Добавляем первую настоящую обязанность: на каждый запрос приходит валидный HS256-токен, и гейтвей обязан его проверить. Здесь пути расходятся. api-gateway, Envoy и Kong умеют проверять JWT сами — встроенным валидатором или плагином. Nginx и Traefik не имеют встроенной проверки и вынуждены на каждый запрос синхронно спрашивать внешний auth-сервис (auth_request / ForwardAuth), который в тесте отвечает только «да».

Цена авторизации: встроенная vs внешняязапросов / секунду · c300
api-gateway (встроенный JWT)нативный JWT (Envoy, Kong)внешний auth-сервис (Nginx, Traefik)светлее = без auth
010k20k28kapi-gateway · без auth · 24 304 запр/сapi-gateway · JWT встроен · 20 641 запр/сapi-gateway−15%Envoy · без auth · 25 272 запр/сEnvoy · jwt_authn · 20 290 запр/сEnvoy−20%Kong · без auth · 25 793 запр/сKong · плагин jwt · 18 331 запр/сKong−29%Nginx · без auth · 27 216 запр/сNginx · auth_request (внешний сервис) · 2 849 запр/сNginx−89%Traefik · без auth · 24 811 запр/сTraefik · ForwardAuth (внешний сервис) · 1 541 запр/сTraefik−94%
Валидный HS256-токен на каждый запрос. Нативная проверка стоит 15–29%; вынесенный auth-сервис (auth_request / ForwardAuth) — 89–94%.

Замеры авторизации — отдельная серия со своей базой «без auth»: api-gateway стартует в ней с 24 304 запросов в секунду, а не с 24 068 из базового графика. Сравнение корректно внутри одной серии — проценты показывают цену авторизации, а не расхождение между прогонами. Теперь базы обеих серий почти совпадают, так что расхождение между прогонами практически не влияет на выводы.

Результат резко разводит две архитектуры. Встроенная проверка стоит 15–29%: api-gateway теряет 15% (24 304 → 20 641 запросов в секунду), Envoy — 20%, Kong — 29%. Вынесенный auth-сервис стоит 89–94%: Nginx падает с 27 216 до 2 849, Traefik — с 24 811 до 1 541. Дело не в том, что Nginx «медленный» — на голом прокси он быстрее всех. Дело в лишнем синхронном сетевом хопе на каждом запросе: пока auth-сервис отвечает, соединение ждёт.

Вывод шага: авторизация — это не функция, которую можно «добавить потом» без последствий. Если она не встроена, вы платите за неё сетевой задержкой на горячем пути, и цена измеряется не процентами, а разы. Выбор гейтвея здесь — выбор архитектуры, а не сравнение качества продуктов.

Шаг 3. Добавляем правила, права и аудит

Авторизация — только первая обязанность. Дальше на гейтвей ложится проверка ролей и прав, лимиты, кэш прав и аудит. Цена каждой надстройки — относительно режима без авторизации (для RBAC — относительно режима с JWT), на тех же 300 соединениях:

Что добавляемЦена
JWT-аутентификация−15%
RBAC по ролям из claims−0.5% (к JWT)
Rate limiting по роутам−2.4%
Кэш permission-сервиса~0% (без кэша — −93%)
Аудит-вебхуки: HTTP с батчингом−3% (без батчинга — −69%)
Аудит через NATS−11%

Две строки здесь важнее остальных. Кэш permission-сервиса даёт ~0% в установившемся режиме: проверка прав не бесплатна сама по себе, но при кэше она перестаёт быть сетевым хопом на каждый запрос. Без кэша внешний permission-сервис стоил бы 93% — это верхняя граница цены внешней авторизации (89–94%). Аудит устроен похоже: если слать HTTP-вебхук на каждое событие, это стоит 69% пропускной способности, но батчинг схлопывает события в пачки и снижает цену до 3%. Доставка при этом сохраняется за счёт backpressure: при переполнении очередь притормаживает поток, а не теряет события. Через NATS тот же аудит стоит 11%.

Теперь сравним, чем каждая архитектура отвечает на четыре ключевые обязанности продакшен-гейтвея; последнюю — service discovery — разберём на следующем шаге:

Обязанностьapi-gatewayTraefikNginxEnvoyKong
Путь проверки JWT✓ встроено• ForwardAuth / плагин— нужен njs/Lua• фильтр jwt_authn✓ плагин jwt
RBAC и права✓ встроено• фильтр RBAC/OPA• плагины ACL/OPA
Аудит-события✓ NATS + HTTP, встроено• access-log/tap• через плагины
Service discovery✓ Docker/Podman по labels✓ ключевая фича• ingress-контроллер✓ xDS/Consul/K8s• ingress-контроллер

✓ — есть из коробки · • — частично / через плагин или внешний сервис · — — нет

Полностью встроенный набор из четырёх обязанностей есть только у api-gateway. Envoy закрывает JWT, RBAC и аудит нативными фильтрами, но за discovery отвечает отдельный control plane (xDS/Consul/K8s); Nginx и Traefik для проверки токена обращаются к внешнему сервису; Kong подключает JWT плагином. Вывод шага: цена встроенных функций предсказуема и мала — проценты; цена пристроенных — сетевые хопы и лишние компоненты, то есть разы.

Шаг 4. Убираем ручное управление маршрутами

Последняя обязанность — операционная. Пока сервисов мало, маршруты можно прописывать руками в конфиге гейтвея. Но в проде сервисы появляются и исчезают при деплое, и ручной список таргетов становится источником ошибок: забытый маршрут — это 502, лишний — трафик в никуда. Поэтому api-gateway умеет находить сервисы сам: подключается к Docker/Podman через socket и строит роуты по labels, которыми сервис описывает себя:

labels:
  gateway.enable: "true"
  gateway.name: "blog"
  gateway.port: "8085"
  gateway.router.api.path_prefix: "/api/blog"
  gateway.router.api.auth.required: "false"

На один сервис можно описать несколько роутов с ролями и лимитами, а изменения подхватываются по событиям контейнеров — без перезапуска гейтвея. Последний удачный результат discovery записывается на диск и применяется при старте, поэтому маршруты переживают рестарт даже при недоступном Docker: discovery не становится единой точкой отказа.

Насколько быстро это происходит по сравнению с Traefik, у которого discovery — ключевая фича:

Service discovery: реакция на изменение подамиллисекунды
api-gatewayTraefikсветлее = под появился · насыщенно = под убран
05001000150020002500api-gateway · контейнер появился → роут готов · 720 мсapi-gateway · контейнер упал → роут убран · 650 мсapi-gateway720 / 650 мсTraefik · контейнер появился → роут готов · 310 мсTraefik · контейнер упал → роут убран · 2 210 мсTraefik310 / 2210 мс
Docker-провайдеры. api-gateway переключается симметрично ~0.65–0.72 с (debounce 500 мс, тюнится); Traefik быстро добавляет роут, но убирает за ~2.2 с.

api-gateway реагирует симметрично: новый контейнер становится доступен за ~0.72 с, пропавший убирается за ~0.65 с (поведение discovery.debounce, тюнится). Traefik добавляет роут быстрее — за ~0.31 с, но удаляет его за ~2.2 с: throttle Docker-провайдера. Вывод шага: важно не только то, как быстро гейтвей видит новый сервис, но и как быстро он перестаёт слать трафик на мёртвый. Асимметрия Traefik означает окно в несколько секунд, когда запросы уходят на контейнер, которого уже нет.

Что в итоге получает команда

Соберём аргумент целиком. По базовой скорости api-gateway и остальные — один класс: отставание от Nginx 12%, и оно не растёт под нагрузкой. Эта разница не бесплатна, но и не решающая. Решающим становится следующий шаг: если авторизация встроена, она стоит 15–29%; если её приходится выносить в отдельный сервис, цена — 89–94%, потому что каждый запрос ждёт сетевой ответ. То же повторяется с правами, кэшем и аудитом: встроенные механизмы стоят проценты, пристроенные — хопы и компоненты.

Отсюда практический вывод для выбора архитектуры. api-gateway — не «самый быстрый прокси»: на голом замере он уступает Nginx. Его ценность в том, что он остаётся в одном классе по скорости, когда берёт на себя авторизацию, права, аудит и discovery, — то есть в том режиме, в котором гейтвей и живёт в проде. Команда получает один компонент вместо связки «прокси + auth-сервис + permission-сервис + контроллер discovery» и платит за это 12% базовой скорости, а не разы на горячем пути. Discovery при этом ведёт себя предсказуемо: новый контейнер становится доступен за ~0.72 с, пропавший убирается за ~0.65 с, а последнее удачное состояние хранится на диске и переживает рестарт гейтвея даже при недоступном Docker.

Если ваш сценарий — раздавать статику или терминировать TLS без проверки токенов, Nginx остаётся разумным выбором. Если гейтвей должен понимать, кто пришёл и что ему можно, — считайте не голый RPS, а цену авторизации: именно она определяет, сколько запросов в секунду выдержит система после того, как вы добавите всё, что нужно продакшену.

Локальный бенчмарк · wrk, Docker, ядра закреплены через cpuset · лучший из 5 прогонов на освобождённом железе · полная методология

Похожее