Настройка производительности Nginx: оптимизация рабочих процессов и соединений
Настройте рабочие процессы Nginx, рабочие соединения, лимиты файлов, поведение keepalive и пропускную способность upstream без гаданий.
Настройка производительности Nginx: оптимизация рабочих процессов и соединений
Настройка производительности Nginx часто начинается с двух параметров: рабочие процессы и рабочие соединения. Эти настройки определяют, сколько запросов ваш сервер может обрабатывать одновременно, поэтому небольшие ошибки могут проявляться в виде медленных страниц, остановленных загрузок или ошибок соединения во время пиков трафика.
Хорошая новость в том, что вам не нужно гадать наугад. Вы можете настроить Nginx, сопоставив его модель рабочих процессов с вашим CPU, лимитами файлов, шаблоном трафика и поведением вышестоящего приложения.
Как рабочие процессы Nginx обрабатывают трафик
Nginx использует мастер-процесс и один или несколько рабочих процессов. Мастер-процесс читает конфигурацию, запускает рабочие процессы и обрабатывает перезагрузки. Рабочие процессы выполняют фактическую обработку запросов.
Каждый рабочий процесс может обрабатывать множество соединений, поскольку Nginx использует событийно-ориентированную модель. Это отличается от старых веб-серверов, которым часто требовался один процесс или поток на запрос. Один рабочий процесс Nginx может поддерживать тысячи idle-соединений keepalive, если операционная система это позволяет.
Две основные директивы обычно размещаются в /etc/nginx/nginx.conf:
worker_processes auto;
events {
worker_connections 1024;
}
worker_processes auto; указывает Nginx создавать по одному рабочему процессу на каждое доступное ядро CPU. Для большинства современных Linux-серверов это правильная отправная точка. Это позволяет избежать жесткого кодирования значения, которое становится неверным при изменении размера виртуальной машины.
worker_connections задает максимальное количество одновременных соединений, которые может открыть каждый рабочий процесс. Примерный верхний предел:
worker_processes * worker_connections
Если у вас 4 рабочих процесса и 4096 рабочих соединений, теоретический максимум составляет 16 384 соединения. В реальной жизни используемое число ниже, поскольку трафик обратного прокси может использовать как клиентские, так и вышестоящие соединения.
Например, если Nginx проксирует трафик к приложению Node.js, один запрос пользователя может потреблять одно клиентское соединение плюс одно вышестоящее соединение. Это означает, что 16 384 открытых соединений могут поддерживать около 8 000 активных проксированных запросов, в зависимости от keepalive и времени запросов.
Выбор значений рабочих процессов и соединений
Начните с worker_processes auto, если у вас нет особой причины поступать иначе. Ручная установка этого значения выше количества ядер CPU редко помогает. Это может увеличить переключение контекста и ухудшить производительность под нагрузкой.
Затем настройте worker_connections в зависимости от ожидаемой конкурентности. Для тихого внутреннего инструмента может быть достаточно 1024. Для публичного сайта за балансировщиком нагрузки может потребоваться 4096, 8192 или больше.
Практический базовый уровень для многих производственных серверов выглядит так:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
worker_rlimit_nofile увеличивает лимит файловых дескрипторов, доступных рабочим процессам Nginx. Это важно, потому что каждый сетевой сокет использует файловый дескриптор. Если лимит операционной системы остается низким, простое увеличение worker_connections не поможет.
Вам также следует проверить лимит менеджера служб. В системах systemd Nginx может потребовать переопределение, например:
[Service]
LimitNOFILE=65535
После изменения лимитов systemd перезагрузите systemd и перезапустите Nginx. Для более широкого справочника команд см. Команды управления службой Nginx.
Будьте осторожны с multi_accept on. Он позволяет рабочему процессу принимать как можно больше новых соединений после получения уведомления о готовности. Это может помочь во время всплесков, но это не магия. Если ваше вышестоящее приложение медленное, более быстрое принятие соединений может только быстрее заполнить очереди.
Лимиты операционной системы, влияющие на Nginx
Настройки Nginx работают поверх лимитов Linux. Если эти лимиты слишком малы, Nginx упрется в потолок, даже если его собственная конфигурация выглядит щедрой.
Проверьте эти области при настройке:
- Лимит открытых файлов для процесса Nginx
- Настройки сетевой очереди ядра
- Доступность эфемерных портов для интенсивного прокси-трафика
- Поведение keepalive вышестоящих серверов
- Значения тайм-аута бездействия балансировщика нагрузки
Лимит открытых файлов — самый распространенный блокировщик. Если Nginx регистрирует сообщения типа worker_connections are not enough или too many open files, вам нужно проверить как лимиты Nginx, так и systemd.
Настройки очереди имеют значение, когда много клиентов подключаются одновременно. Если очередь принятия ядра заполняется, пользователи могут видеть тайм-ауты соединения, даже если загрузка CPU выглядит нормальной. Значения, такие как net.core.somaxconn и net.ipv4.tcp_max_syn_backlog, часто пересматриваются при настройке для высокого трафика.
Не копируйте большие значения ядра из случайных примеров без тестирования. Небольшой команде, обслуживающей один API-сервер, не нужны те же настройки, что и узлу CDN. Настраивайте шагами, измеряйте и ведите записи.
Есть еще одна деталь, которая сбивает людей с толку: лимит соединений Nginx — не единственный лимит соединений на пути. Облачный балансировщик нагрузки имеет тайм-ауты бездействия. Среда выполнения контейнера может иметь лимиты трансляции сетевых адресов. Бэкенд-приложение может иметь свой пул рабочих процессов или пул соединений с базой данных. Если Nginx может принять 20 000 соединений, но приложение может обработать только 200 одновременных запросов, пользователи все равно будут ждать.
Вот почему изменение настройки соединений должно включать быструю сквозную проверку. Запустите небольшой нагрузочный тест с хоста вне сервера, наблюдайте за активными соединениями Nginx, а также за бэкендом. Если задержка бэкенда резко возрастает, пока Nginx спокоен, прокси выполняет свою работу, а следующий лимит находится за ним.
Настройка для рабочих нагрузок обратного прокси
Многие серверы Nginx действуют как обратные прокси перед серверами приложений. В этой роли поведение вышестоящих серверов имеет такое же значение, как и емкость Nginx.
Используйте upstream keepalive, когда Nginx многократно обращается к одному и тому же пулу бэкендов:
upstream app_backend {
server 127.0.0.1:3000;
keepalive 32;
}
server {
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://app_backend;
}
}
Это снижает затраты на открытие новых соединений с бэкендом. Это особенно полезно, когда ваше приложение получает много мелких запросов, например, API-вызовы с панели управления.
Также проверьте значения тайм-аута. Очень длинные тайм-ауты прокси могут занимать рабочие соединения после того, как клиенты исчезли или приложения перестали отвечать. Очень короткие тайм-ауты могут нарушить работу законных медленных запросов. Сопоставляйте значения тайм-аута с рабочей нагрузкой вместо использования одного значения по умолчанию везде.
Практический сценарий: ваш сайт быстр большую часть дня, но замедляется во время рассылки новостей. CPU загружен только на 35%, но журналы Nginx показывают предупреждения о соединениях. Это указывает не на сырой CPU, а на лимиты соединений, файловые дескрипторы или очереди upstream. Увеличение рабочих соединений может помочь, но только если приложение и ОС могут поддерживать дополнительную нагрузку.
Другой распространенный сценарий — приложение панели управления, которое делает много мелких API-вызовов из каждой вкладки браузера. Десять человек могут создавать сотни коротких запросов. В этом случае upstream keepalive часто важнее, чем простое увеличение worker_connections, потому что повторная настройка TCP для бэкенда становится ненужными накладными расходами.
Для службы загрузки файлов история иная. Небольшое количество пользователей может удерживать соединения открытыми в течение длительного времени при загрузке больших файлов. Вам может потребоваться достаточно рабочих соединений для длительных передач, но также следует проверить sendfile, пропускную способность диска, пропускную способность сети и поведение тайм-аута клиента.
Для приложений WebSocket или long-polling бездействующие соединения являются нормой. Высокое число Waiting не обязательно плохо. Вопрос в том, оставляют ли эти бездействующие соединения достаточно емкости для новых запросов и остается ли использование памяти предсказуемым.
Чтение stub_status во время настройки
Модуль stub_status дает вам быстрый обзор поведения соединений:
Active connections: 291
server accepts handled requests
1162447 1162447 4496426
Reading: 6 Writing: 17 Waiting: 268
Reading означает, что Nginx читает заголовки запросов. Устойчиво высокое число может указывать на медленных клиентов, большие заголовки или атаку. Writing означает, что Nginx отправляет ответы. Это может возрастать, когда клиенты медленно получают данные или когда ответы большие. Waiting означает бездействующие соединения keepalive. Это число может быть высоким на здоровых сайтах.
Счетчики accepts и handled обычно должны двигаться вместе. Если принятые соединения растут, но обработанные отстают или появляются ошибки, проверьте лимиты рабочих процессов и лимиты файловых дескрипторов. Также проверьте, не отбрасывает ли ядро соединения до того, как Nginx сможет их обработать.
Эти счетчики базовые, но они полезны, потому что отделяют давление соединений от давления CPU. Если активные соединения низкие, а CPU высокий, проблема, вероятно, не в worker_connections. Если активные соединения высокие, а CPU низкий, более вероятны лимиты соединений, поведение keepalive, очереди upstream или медленные клиенты.
Безопасная базовая конфигурация
Для небольшого производственного сервера я бы предпочел начать консервативно и измерять:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
http {
keepalive_timeout 30s;
keepalive_requests 1000;
}
Это не универсальная лучшая конфигурация. Это разумная отправная точка для многих обычных рабочих нагрузок обратного прокси. Очень маленькой виртуальной машине может потребоваться меньше. Занятому краевому прокси может потребоваться гораздо больше. Важно то, что worker_connections и worker_rlimit_nofile согласованы.
После применения базовой конфигурации сравните показатели до и после при аналогичном трафике. Не оценивайте изменение настройки по одной удачной минуте после перезагрузки. Смотрите на задержку p95 или p99, частоту ошибок, CPU, память и очереди бэкенда в течение достаточного времени, чтобы увидеть реальное поведение.
Ошибки, которые делают настройку соединений случайной
Первая ошибка — подсчет запросов вместо соединений. Браузер может повторно использовать одно соединение для нескольких запросов, а HTTP/2 может мультиплексировать множество запросов через одно соединение. Медленный клиент также может удерживать соединение открытым, выполняя очень мало полезной работы. Это означает, что "мы получаем только 500 запросов в секунду" не говорит вам, сколько соединений нужно Nginx.
Вторая ошибка — забывать о вышестоящих соединениях. Если Nginx обслуживает статические файлы, большинство соединений являются клиентскими. Если Nginx проксирует приложение, активные запросы часто также требуют сокетов бэкенда. Если вы используете keepalive для upstream, некоторые соединения с бэкендом остаются открытыми для повторного использования. Это хорошо, но это все равно потребляет файловые дескрипторы с обеих сторон.
Третья ошибка — увеличение лимитов Nginx без проверки приложения. Предположим, Nginx теперь может принимать 12 000 одновременных соединений, но приложение имеет 16 рабочих процессов и пул соединений с базой данных из 50 соединений. Nginx будет принимать больше работы, чем приложение может завершить. Пользователи могут видеть меньше немедленных ошибок соединения, но задержка может ухудшиться, потому что запросы ждут дольше в очередях.
Четвертая ошибка — использование длинных тайм-аутов keepalive везде. Keepalive полезен, потому что позволяет избежать повторной настройки TCP и TLS. Но очень длинный тайм-аут может оставить много бездействующих сокетов открытыми после пика трафика. На богатом памятью краевом прокси это может быть нормально. На маленькой виртуальной машине это может вытеснить активную работу. Если вы видите огромное количество Waiting и низкое повторное использование запросов, попробуйте более короткий keepalive_timeout и измерьте снова.
Примеры устранения неполадок
Если журнал ошибок говорит worker_connections are not enough, проверьте настроенное значение, количество рабочих процессов и лимит файлов процесса:
grep -R "worker_connections\\|worker_processes\\|worker_rlimit_nofile" /etc/nginx/nginx.conf /etc/nginx/conf.d
cat /proc/$(pgrep -o nginx)/limits | grep "open files"
Команда pgrep -o nginx обычно находит самый старый процесс Nginx, который часто является мастер-процессом. В некоторых системах вы можете предпочесть systemctl status nginx, чтобы увидеть основной PID.
Если журнал ошибок говорит too many open files, не просто увеличивайте worker_connections. Процесс достигает лимита дескрипторов. Добавьте или измените LimitNOFILE для службы systemd, перезагрузите systemd и перезапустите Nginx, чтобы новый лимит был фактически применен:
sudo systemctl edit nginx
sudo systemctl daemon-reload
sudo systemctl restart nginx
Если пользователи видят тайм-ауты, но у Nginx есть свободный CPU и нет предупреждений о соединениях, ищите за Nginx. Проверьте время ответа upstream в журналах доступа. Проверьте пул рабочих процессов приложения. Проверьте соединения с базой данных. Обратный прокси может плавно принимать трафик, в то время как реальное узкое место — насыщенный бэкенд.
Если всплеск вызывает сброс соединений до того, как запросы появятся в журналах доступа, проблема может быть раньше обработки запросов Nginx. Проверьте настройки очереди ядра, журналы балансировщика нагрузки, таблицы состояния межсетевого экрана и защиту от SYN-флуда. Nginx не может зарегистрировать запрос, который он никогда не получил.
Как безопасно тестировать изменения
Никогда не настраивайте продакшн, редактируя и надеясь. Сначала проверьте синтаксис:
sudo nginx -t
Затем перезагрузите Nginx, чтобы активные соединения обрабатывались корректно:
sudo systemctl reload nginx
Следите за журналом ошибок после каждого изменения:
sudo tail -f /var/log/nginx/error.log
Вам также следует отслеживать задержку запросов, частоту 4xx и 5xx, активные соединения, CPU, память и время ответа upstream. Изменение настройки, которое увеличивает емкость соединений, но повышает задержку приложения, может не быть реальным выигрышем.
Для более глубоких шагов проверки см. тестирование конфигураций Nginx.
Когда привлекать специалиста
Обращайтесь к опытному DevOps-инженеру или специалисту по веб-производительности, когда ошибки Nginx продолжаются после базовой настройки, когда пики трафика влияют на доход или когда вы изменяете сетевые настройки ядра на производственной системе. То же самое относится к настройке Nginx перед платежными потоками, системами входа или критическими API.
Профессиональная помощь также полезна, когда узкое место неясно. Nginx может выглядеть как проблема, когда реальная проблема — медленная база данных, исчерпанный пул приложений upstream, перегруженный уровень завершения TLS или несоответствие тайм-аута балансировщика нагрузки.
Ключевой вывод прост: настройте рабочие процессы в соответствии с CPU, настройте рабочие соединения в соответствии с конкурентностью и убедитесь, что лимиты файлов Linux поддерживают и то, и другое. Изменяйте один слой за раз, тестируйте конфигурацию перед перезагрузкой и измеряйте реальный трафик вместо того, чтобы полагаться на теоретические максимумы.