Архитектура Nginx: как воркеры используют epoll
Nginx обслуживает тысячи соединений не за счёт потока на каждый запрос, а благодаря процессам-воркерам и событийной модели. Разбираем путь соединения через master, worker и epoll, пределы worker_connections и симптомы неверной настройки.

Один процесс Nginx может держать тысячи TCP-соединений, не создавая отдельный поток для каждого клиента. В Linux за это отвечает связка из процессов-воркеров и механизма epoll: master управляет жизненным циклом, worker принимает события, а ядро сообщает, какие сокеты готовы к чтению или записи. Ошибка в понимании этой схемы приводит к ложным выводам: увеличение worker_processes не всегда ускоряет сайт, а значение worker_connections не равно числу пользователей.
Из каких частей состоит Nginx
Разбор ниже относится к Nginx Open Source 1.26.x на Linux. На уровне архитектуры схема сохраняется и в соседних версиях, но имена и значения директив стоит сверять с конфигурацией конкретной сборки.
Master управляет, worker обслуживает
После запуска главный процесс, или master, читает конфигурацию, открывает слушающие сокеты и создаёт worker-процессы. Он не обрабатывает HTTP-запросы в обычном режиме. Его задачи — запустить и остановить workers, принять сигнал на перечитывание конфигурации, корректно завершить старые процессы после reload и следить за их состоянием.
Worker выполняет основную работу:
- принимает новые соединения на слушающем сокете;
- читает HTTP-запрос и заголовки;
- обращается к upstream, если Nginx работает как reverse proxy;
- отправляет ответ клиенту частями, когда сокет готов к записи;
- закрывает соединение или оставляет его для keep-alive.
Worker не должен надолго блокироваться на одном клиенте. Если обработчик ждёт медленный диск, синхронный внешний вызов или неправильно настроенный модуль, страдают все соединения, попавшие в этот процесс. Поэтому модель Nginx называют событийной, но это не означает, что любая операция внутри модуля автоматически становится неблокирующей.
Главное ограничение Nginx — не количество запросов в секунду само по себе, а время, на которое каждый worker занят обработкой события.
Что происходит внутри worker
У каждого worker есть собственный цикл обработки событий. Упрощённо он повторяет четыре действия: передать ядру список интересующих сокетов, дождаться готовых событий, выполнить обработчики и снова зарегистрировать интерес к будущим событиям.
Почему worker не ждёт каждый сокет отдельно
Наивная модель выглядит так: процесс принимает соединение, блокируется на чтении, получает запрос и только после этого переходит к следующему клиенту. Для сотен медленных клиентов это означало бы сотни потоков или процессов, большую стоимость переключений контекста и расход памяти.
В событийной модели worker не читает каждый сокет напрямую в ожидании данных. Он передаёт ядру набор дескрипторов и получает уведомление, когда операция может быть выполнена без блокировки. Один цикл может по очереди обслужить готовые соединения, а не простаивать на первом медленном клиенте.
Роль epoll в Linux
epoll — интерфейс Linux для ожидания событий на большом количестве файловых дескрипторов[1]. Nginx регистрирует сокеты, интересующие его события и получает от ядра только готовые дескрипторы. Это снижает объём работы по сравнению с механизмами, которым приходится проверять весь список сокетов на каждом проходе.
В конфигурации Nginx механизм выбирается директивой use в блоке events. На Linux обычно используется epoll. Если директиву не задавать, Nginx сам выбирает доступный эффективный механизм. Жёстко прописывать use epoll имеет смысл только после проверки платформы и требований к переносимости конфигурации.
Файловый дескриптор — числовой идентификатор открытого ресурса процесса: TCP-сокета, файла, pipe или другого объекта, который ядро разрешает читать и записывать.
Как распределяются соединения между workers
Все workers обычно наследуют слушающие сокеты от master. Когда приходит новый клиент, возникает вопрос: какой процесс должен его принять. На Linux Nginx может использовать механизм, при котором несколько workers ждут события на одном сокете, а ядро будит подходящий процесс. Для некоторых сценариев применяется accept_mutex — внутренняя координация, уменьшающая конкуренцию workers за новые соединения.
Важно отличать распределение новых подключений от обработки уже установленного соединения. После accept конкретный сокет обслуживает тот worker, которому он достался. Если один клиент держит долгий WebSocket или медленное proxy-соединение, это соединение продолжает занимать ресурсы именно этого процесса.
Сколько ставить worker_processes
Директива worker_processes задаёт число workers. Значение auto позволяет Nginx ориентироваться на число доступных CPU. Это хороший старт, но не универсальная формула производительности: контейнер может видеть не тот набор CPU, а приложение может конкурировать с Nginx за те же ядра.
На машине, где Nginx только принимает TLS и проксирует запросы, увеличение workers обычно полезно до числа доступных вычислительных ядер. На сервере с тяжёлой логикой, сжатием, TLS и несколькими сервисами рядом результат нужно проверять нагрузочным тестом. Слишком большое число workers добавляет конкуренцию за CPU и память, но не создаёт дополнительных ядер.
worker_connections — не лимит пользователей
worker_connections ограничивает количество одновременно открытых соединений на один worker, включая не только клиентов, но и соединения к upstream. Для reverse proxy один пользователь может занимать как минимум два дескриптора: клиентский и серверный.
| Сценарий | Что занимает дескрипторы | Практическое следствие |
|---|---|---|
| Статический файл | Соединение клиента и открытый файл | Лимит упирается в сокеты и файловые дескрипторы |
| Reverse proxy | Клиентский сокет и соединение с upstream | Оценивать нужно обе стороны, а не только клиентов |
| Keep-alive | Открытый клиентский сокет даже между запросами | Долгие простои расходуют лимит соединений |
| WebSocket | Долгоживущий клиентский сокет и, часто, upstream | Небольшое число клиентов может занять заметную долю лимита |
Теоретическая верхняя граница выглядит как worker_processes × worker_connections, но это не обещание Nginx принять столько клиентов. Её ограничивают системные лимиты открытых файлов, память, backlog слушающего сокета, число соединений upstream и настройки конкретного модуля.
Что измерять под нагрузкой
Архитектуру нельзя оценить только по средней задержке. Снимите базовые показатели до изменения конфигурации, затем повторите тест с тем же числом соединений, размером ответа и распределением запросов.
- Разделите CPU по процессам. Проверьте, работают ли все workers или один процесс постоянно загружен сильнее остальных.
- Посмотрите активные и ожидающие соединения. Сопоставьте их с числом клиентов и значением
worker_connections. - Проверьте ошибки. Ищите сообщения о достижении лимита открытых файлов, переполнении очереди, закрытых upstream-соединениях и таймаутах.
- Сравните p95 и p99 задержки. Среднее время может не показать редкие зависания из-за медленных клиентов или upstream.
- Проверьте системные лимиты. Сопоставьте число дескрипторов процесса с лимитами systemd, контейнера и ядра Linux.
Если после увеличения workers CPU простаивает, а задержка растёт, причина, вероятно, не в количестве процессов. Ищите блокирующую операцию, медленный upstream, TLS, диск, ограничение файловых дескрипторов или сетевой лимит. Если workers загружены неравномерно, отдельно проверьте распределение соединений и характер трафика.
Где событийная модель ломается
Медленный клиент
Клиент, который принимает ответ по несколько секунд, держит сокет и часть памяти. Сам по себе такой клиент не обязан блокировать worker, но большое число долгих соединений быстро расходует лимиты. Для публичного сервиса нужны осмысленные таймауты чтения и записи, а не бесконечное ожидание.
Медленный upstream
Nginx может эффективно распределять события, но не ускорит базу данных или приложение. Если upstream отвечает медленно, workers продолжают обслуживать множество открытых состояний и буферов. Смотрите отдельно время подключения, ожидания ответа и передачи тела: один общий таймаут скрывает, где возникла задержка.
Блокирующий модуль или операция
Событийная модель не отменяет поведения подключённых модулей. Синхронное чтение большого файла, внешний вызов или тяжёлая обработка могут занять worker. В такой ситуации добавление workers лишь распределит проблему между процессами и увеличит потребление ресурсов.
Неверная оценка лимитов
Сообщение о невозможности открыть файл не всегда означает нехватку дискового места. Это может быть лимит файловых дескрипторов самого процесса или сервиса запуска. Сначала определите, какой лимит сработал, затем меняйте его на уровне ОС или systemd. Одного увеличения worker_connections недостаточно.
Что делать дальше
Начните с фиксации текущих значений worker_processes, worker_connections, таймаутов и системного лимита открытых файлов. Затем проведите два одинаковых теста: с базовой конфигурацией и с изменённым числом workers. Смотрите не только на RPS, но и на p95/p99, загрузку каждого worker, количество активных соединений и ошибки в error log. Если узкое место оказалось в upstream, настройка epoll его не устранит — следующим шагом станет профилирование приложения или базы.
[1] В Linux epoll отслеживает готовность файловых дескрипторов к операциям ввода-вывода. Это не отдельный серверный поток и не очередь HTTP-запросов, а интерфейс ядра для ожидания событий.
Создатель презентаций: Структура и текст каждого слайда: заголовки-утверждения, одна мысль на слайд, заметки докладчику.
Спросить за 150 ₽Источники: Nginx documentation: Core functionality, Nginx documentation: Events module
Частые вопросы
Нужно ли всегда ставить worker_processes auto?
Почему worker_connections 10000 не означает 10000 пользователей?
Нужно ли вручную прописывать use epoll?
Что изменится, если у меня другая версия Nginx или не Linux?
Что делать, если после увеличения workers сайт не ускорился?
Может ли один медленный клиент положить весь Nginx?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.