Тюнинг соединений в Nginx: поведение под нагрузкой
Nginx может упереться в лимит соединений задолго до загрузки процессоров. Разбираем, как под нагрузкой ведут себя worker_connections, keep-alive, очередь listen и соединения с бэкендом, а также что измерять перед изменением конфига.

При 2 000 одновременных клиентов Nginx может начать отдавать 502 и 504, хотя CPU ещё не занят полностью. Причина часто не в «медленном Nginx», а в том, что keep-alive-соединения заняли файловые дескрипторы, очередь приёма переполнилась или каждый клиент потребовал ещё одно соединение к upstream. Ниже — разбор для nginx Open Source 1.25.x и 1.27.x: что происходит под нагрузкой, какие параметры связаны между собой и как проверять результат без выдуманных цифр.
Сначала определите, какой лимит сработал
Тюнинг соединений начинается не с увеличения worker_connections, а с поиска узкого места. Одно входящее соединение не всегда равно одному файловому дескриптору: при проксировании Nginx обычно держит клиентский сокет и отдельный сокет к серверу приложения.
- Лимит Nginx. Директива
worker_connectionsограничивает число одновременных соединений на один worker. В это число входят не только клиенты, но и соединения к upstream, WebSocket и другие сокеты. - Лимит процесса.
worker_rlimit_nofileзадаёт допустимое число открытых файловых дескрипторов для worker, но не отменяет ограничения systemd, контейнера и операционной системы. - Очередь TCP. Параметр
backlogвlistenзадаёт размер очереди ожидающих подключений. Фактический предел дополнительно зависит от настроек ядра. - Бэкенд. Приложение может исчерпать собственный пул соединений к базе или лимит клиентов, даже если Nginx принимает новые запросы.
Проверяйте конфигурацию командой nginx -t, затем смотрите ошибки в error log, число сокетов через ss и состояние upstream по метрикам приложения. Один график CPU не показывает проблему с очередью или файловыми дескрипторами.
Увеличение лимита соединений не создаёт пропускную способность. Оно лишь позволяет системе дольше принимать работу, которую она может не успевать выполнять.
Как Nginx распределяет соединения между worker
Обычно Nginx запускает несколько worker-процессов и использует событийную модель: процесс не выделяет отдельный поток на каждый сокет, а ждёт готовности большого числа соединений через механизм ОС. Поэтому число worker и число соединений — разные параметры.
Если указано четыре worker и worker_connections 4096, теоретический верхний предел — 16 384 соединения. Это не гарантия для клиентов: часть дескрипторов займут upstream, служебные сокеты и другие открытые файлы. Реальный предел также может оказаться ниже из-за RLIMIT_NOFILE или лимита контейнера.
accept_mutex управляет тем, как worker конкурируют за новые подключения. В актуальных версиях Nginx директива по умолчанию выключена; на системах с эффективным распределением событий это обычно нормальный вариант. Принудительное включение не является универсальным ускорением: оно может уменьшить «стадный эффект», но добавить задержку перед передачей работы свободному worker.
multi_accept позволяет worker принимать сразу несколько новых соединений за одно событие. По умолчанию значение выключено. Включение может помочь при коротких всплесках новых подключений, но способно отнять время у уже обслуживаемых запросов. Проверять его стоит только по latency, числу запросов и загрузке worker, а не по одному показателю accept.
Keep-alive: экономия рукопожатий против занятых дескрипторов
HTTP keep-alive оставляет TCP-соединение открытым после ответа. Это снижает стоимость повторных TCP- и TLS-рукопожатий, но каждое простаивающее соединение продолжает занимать ресурсы. В Nginx параметр keepalive_timeout задаёт время ожидания следующего запроса для клиентского соединения.
Слишком длинный тайм-аут особенно заметен на API с большим числом клиентов: пользователь сделал один запрос, а сокет остаётся открытым десятки секунд. Слишком короткий тайм-аут увеличивает число новых подключений, нагрузку на TLS и вероятность всплесков в очереди. Выбирайте значение по реальному профилю: для браузерного сайта и долгих API-сессий это разные сценарии.
Keep-alive к upstream настраивается отдельно. Директива keepalive в блоке upstream задаёт число простаивающих соединений к серверам группы на один worker, а не общий лимит для всего Nginx. При четырёх worker и значении 64 потенциально сохраняется до 256 idle-соединений к upstream, если они действительно нужны.
Минимальный пример для reverse proxy
Фрагмент рассчитан на nginx Open Source 1.25.x и 1.27.x. Числа — не универсальный рецепт: перед применением их нужно сопоставить с лимитами хоста, числом worker и возможностями приложения.
worker_processes auto;
worker_rlimit_nofile 20000;
events {
worker_connections 4096;
}
http {
upstream application {
server 127.0.0.1:8080;
keepalive 64;
}
server {
listen 80 backlog=2048;
keepalive_timeout 15s;
location / {
proxy_pass http://application;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_connect_timeout 3s;
proxy_read_timeout 30s;
}
}
}
После изменения проверьте конфигурацию через nginx -t и выполните корректную перезагрузку штатным способом вашей системы. Смотрите, не выросли ли ошибки открытия файлов, 502/504 и время ответа. Параметр proxy_read_timeout не ускоряет приложение: он только определяет, сколько Nginx ждёт данные от upstream.
Backlog не равен числу обслуживаемых клиентов
Когда новые подключения приходят быстрее, чем worker успевает их принять, они временно попадают в очереди ядра. listen ... backlog=2048 задаёт пожелание для очереди, но ОС может ограничить его собственным максимумом. Если очередь переполняется, клиент увидит задержку, отказ соединения или повторную попытку — в зависимости от стека, прокси и типа трафика.
Большой backlog полезен для коротких всплесков, но не исправляет медленный upstream. Очередь лишь накапливает работу. Если приложение стабильно обрабатывает меньше запросов, чем приходит, рост backlog увеличит время ожидания и скроет проблему до момента массового тайм-аута.
Отдельный случай — reuseport. Он создаёт отдельный слушающий сокет для каждого worker и может улучшить распределение новых подключений на поддерживаемых ОС. Но результат зависит от ядра, характера трафика и числа worker. Включать его только ради большей цифры соединений не стоит: сначала сравните latency, баланс между worker и потери подключений.
Что измерять до и после изменений
Сравнение «до и после» имеет смысл только при одинаковом сценарии нагрузки: тот же маршрут, размер ответа, число клиентов, длительность теста и лимиты бэкенда. Если таких замеров нет, не подставляйте придуманные значения — зафиксируйте базу и повторите тест.
- долю ответов 4xx, 5xx, 502 и 504;
- время ответа по перцентилям, а не только среднее;
- число активных, ожидающих и закрывающихся TCP-соединений;
- занятые файловые дескрипторы и ошибки вида
too many open files; - загрузку каждого worker, а не только среднюю загрузку хоста;
- число соединений и очередь запросов на upstream, базу данных и приложение.
Для диагностики можно использовать встроенный модуль stub_status, если он собран и опубликован безопасно. Не выставляйте служебный endpoint в интернет без контроля доступа. Статусы Nginx показывают не всё: причины задержек upstream нужно подтверждать метриками самого приложения.
Где настройка ломается
Лимит worker выше лимита файлов
Если увеличить worker_connections, но оставить низкий лимит дескрипторов процесса, worker упрётся в ОС раньше. В логах появится ошибка открытия файла или сокета. Проверьте лимиты службы, контейнера и пользователя, под которым работает Nginx; одной директивы в nginx.conf недостаточно.
Долгие соединения заняли весь пул
WebSocket, SSE и медленные загрузки могут держать соединения минуты или часы. Для них общий расчёт по коротким HTTP-запросам не подходит. Выделяйте отдельные location, считайте их соединения отдельно и не уменьшайте тайм-ауты вслепую: это может оборвать легитимные долгие сессии.
Upstream не поддерживает выбранную схему
Клиентский keep-alive и keep-alive между Nginx и приложением — независимые вещи. Если приложение или промежуточный прокси закрывает соединения, сохранённые upstream-сокеты не дадут ожидаемого эффекта. Для каждого backend проверяйте фактический протокол, тайм-ауты и лимит соединений.
Один worker перегружен
При неравномерном распределении подключений часть worker может быть занята, пока остальные простаивают. Причиной бывают длинные запросы, WebSocket, особенности ядра или слушающего сокета. В таком случае увеличение общего числа worker не гарантирует улучшения — сначала найдите, какой тип соединений удерживает процесс.
Когда менять какой параметр
| Симптом | Проверить | Первое действие | Риск изменения |
|---|---|---|---|
| Дескрипторы заканчиваются | Лимиты процесса и число сокетов | Согласовать worker_rlimit_nofile, лимит службы и worker_connections | Хост примет больше работы, чем выдержит приложение |
| Отказы при коротком всплеске подключений | Очередь listen и ошибки ядра | Проверить backlog, системный максимум и время accept | Большая очередь увеличит ожидание |
| Много idle-клиентов | Профиль keep-alive и число активных сокетов | Подобрать keepalive_timeout по типу трафика | Частые переподключения и дополнительный TLS |
| Много новых соединений к приложению | Стоимость handshake и лимит backend | Проверить upstream keepalive и HTTP-версию | Сокеты накапливаются на каждом worker |
Файловый дескриптор — числовой идентификатор открытого ресурса процесса: TCP-сокета, файла или другого объекта ОС. Поэтому лимит «соединений» в Nginx связан не только с сетью: логи и служебные файлы тоже используют тот же ресурс.
Что делать дальше
Сначала снимите базовые значения на рабочем трафике: активные соединения, ошибки, перцентили задержки, дескрипторы и состояние upstream. Затем меняйте один параметр за раз и повторяйте одинаковый тест. После тюнинга поставьте алерты на too many open files, рост 502/504, заполнение очереди приложения и дисбаланс между worker. Инвалидация кэша, лимиты базы данных и настройка TLS — отдельные темы: они влияют на результат, но не заменяют диагностику соединений.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: Nginx documentation: Core functionality, Nginx documentation: HTTP upstream module
Частые вопросы
Достаточно ли увеличить worker_connections, чтобы Nginx принял больше клиентов?
Как понять, что сработал лимит файловых дескрипторов?
Нужно ли включать reuseport и multi_accept на любом сервере?
Почему keep-alive иногда ухудшает ситуацию?
Что делать, если после увеличения лимитов появились 502 и 504?
Подойдут ли эти значения для nginx 1.21 или старой сборки дистрибутива?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.