NGINX NodeJS PM2 — 502 bad gateway — ошибка connect() failed (111: Connection refused) while connecting to upstream — efim360.ru

NGINX NodeJS PM2 - 502 bad gateway - ошибка connect() failed (111: Connection refused) while connecting to upstream

В связке технологий (NGINX, NodeJS, PM2) на сайте стала периодически появляться ошибка 502 bad gateway, которую возвращал веб-сервер NGINX, который работал в режиме "пробрасывающего" запросы сервера на NodeJS-приложение. В логах сервера NGINX эта ошибка была оформлена как "connect() failed (111: Connection refused) while connecting to upstream".

Управление NodeJS-приложениями было доверено PM2. PM2 - это демон-менеджер процессов, который поможет вам управлять вашим приложением и поддерживать его в сети 24/7.

Источник проблем не удалось до конца идентифицировать (хотя и были предположения), но получилось на 100% избавиться от 502 ошибки в процессе общения NGINX с NodeJS.

Решение проблемы

Шаг № 1 - Включение режима "Cluster Mode" в PM2

В процессе чтения документации по менеджеру процессов PM2 стало ясно, что он умеет работать в режиме "Cluster Mode".

Выдержка из документа:

Кластерный режим ("Cluster Mode") позволяет масштабировать сетевые приложения Node.js (сервер http (s) / tcp / udp) на все доступные ЦП (CPUs) без каких-либо изменений кода. Это значительно увеличивает производительность и надежность ваших приложений в зависимости от количества доступных процессоров. Под капотом здесь используется кластерный модуль Node.js, так что дочерние процессы масштабируемого приложения могут автоматически совместно использовать порты сервера. Дополнительные сведения см. В разделе «Как это работает» в официальной документации Node.js по модулю кластера.

Cluster Mode in PM2 - NodeJS server
Cluster Mode in PM2 - NodeJS server

О чём речь? Простыми словами.

Изначально работающее приложение было запущено стандартной командой от PM2:

$ pm2 start app.js

 

В таком запуске приложение работало в режиме "Fork" (вместо "Cluster") и задействовало всего одно ядро процессора. Ниже пример:

Режим Fork для приложения NodeJS в менеджере процессов PM2
Режим Fork для приложения NodeJS в менеджере процессов PM2

В какой-то момент "запросной" активности этого оказалось недостаточно и в пиковые моменты вываливались 502 ошибки.

Все приложения сначала были остановлены:

$ pm2 stop app_name

После этого все приложения были удалены из процессов:

$ pm2 delete app_name

Затем пустой PM2 был сохранён в качестве "автозагрузки"

$ pm2 startup

...и заморожен

$ pm2 save

 

После этого выделенный сервер ушёл в выключение (не перезагружен), а потом был запущен (включен).

После этого в PM2 было запущено "проблемное" приложение с опцией "-i" и значением "max", которое символизировало "максимальное" доступное количество ядер процессора на этом выделенном сервере.

$ pm2 start app.js -i max

Ядра были автоматически посчитаны и в результате приложение запустило несколько версий себя. После этого решения все "проблемные" ошибки 502 были устранены.

Шаг № 2 - Анализ конфигурационного файла виртуального хоста в NGINX

На всякий случай был проанализирован файл конфигурации виртуального хоста, от имени которого работало приложение. В этом файле были найдены проблемные места.

Директива proxy_http_version в контексте location. Её просто не существовало в конфиге нужного виртуального хоста. Это большая проблема, так как отсутствие пропечатанной директивы proxy_http_version означает то, что она работает в режиме по умолчанию в формате 1.0.

Формат 1.0 не поддерживает ПОСТОЯННЫЕ СОЕДИНЕНИЯ и ПРОВЕРКИ ПОДЛИННОСТИ NTLM. Иными словами NGINX каждый раз устанавливает соединение с NodeJS приложением и говорит "Здравствуйте", когда пробрасывает запрос. Это очень трудозатратно и повышает шанс отсутствия ответа от NodeJS-приложения, если оно в какой-то момент времени занято более важными вещами.

Дополнительно прописали директиву:

location / {
        ...
    	proxy_http_version 1.1;
        ...
    }

Добавление директивы proxy_http_version открыло возможность использования другой директивы (keepalive) в контексте upstream

Задействует кэш соединений для группы серверов.

Выдержка из документа:

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

Следует особо отметить, что директива keepalive не ограничивает общее число соединений с серверами группы, которые рабочие процессы nginx могут открыть. Параметр соединения следует устанавливать достаточно консервативно, чтобы серверы группы по-прежнему могли обрабатывать новые входящие соединения.

upstream my_nodejs_upstream {
    server 127.0.0.1:3001;
    keepalive 64;
}

 

Информационные ссылки

PM2 - Cluster Mode - https://pm2.keymetrics.io/docs/usage/cluster-mode/

Поделись записью