Правильно перечитываем настройки в Nginx
Проблема может показаться надуманной, потому что способ известен с незапамятных времён:
nginx -t && nginx -s reload
Его недостаток заключается в том, что конфигурация последовательно читается три раза:
- сначала в режиме проверки из “nginx -t”,
- затем в режиме проверки из “nginx -s reload”,
- в случае успеха “nginx -s reload” отправляет мастер-процессу SIGHUP, и мастер-процесс также читает настройки, проверяет их, и в случае отсутствия ошибок применяет.
Этим недостатком можно пренебречь, пока размер настроек остаётся небольшим.
Однако с конфигурацией среднего (по нашим меркам) размера он начинает создавать неудобства:
$ date ; nginx -q -T | wc -l ; date
Tue Dec 17 18:57:14 MSK 2019
54651
Tue Dec 17 18:57:25 MSK 2019
Как видно из этого примера, чтение настроек на нашем тестовом сервере занимает 11 секунд, то есть от запуска верхней команды до запуска воркеров с новой конфигурацией пройдёт пол-минуты с лишним.
Увы, но редкий клиент способен ждать в наше время так долго.
В одной из наших предыдущих заметок мы уже объясняли, что чтение конфигурации является одним из главных узких мест Nginx, потому что его нельзя распараллелить, сделать асинхронным или применить какую-то другую из заложенных в Nginx оптимизаций.
Поэтому нижнюю границу в 11 секунд будем считать предельной (это не вполне так, потому что порядок настроек способен влиять на скорость чтения, но поход в эти дебри мы отложим до следующего раза). Как её можно достичь?
Во-первых, если “nginx -s reload” выполняет проверку настроек перед отправкой сигнала мастер-процессу, становится ненужным предварительный “nginx -t”.
Во-вторых, поскольку мастер-процесс самостоятельно проверяет настройки перед применением, можно заменить “nginx -s reload” на простую отправку сигнала:
pkill -HUP -F /var/run/nginx.pid
В этом случае настройки будут читаться всего один раз.
Однако возникает проблема — как обнаруживать, что в настройки закралась ошибка и nginx не сумел их применить? Вариант с проверкой error.log отпадает, потому что Nginx сообщает там о получении сигнала и о найденных ошибках, но об отсутствии ошибок и успешном применении настроек не сообщает.
С другой стороны, что мешает нам вызвать “nginx -t” не до отправки сигнала, а после? При этом и мастер-процесс, и “nginx -t” потратят на чтение настроек по 11 секунд, но они потратят их не последовательно, а одновременно. Таким образом, за минимально возможное время мы и применим настройки, и убедимся, что они верные (а значит, применились):
pkill -HUP -F /var/run/nginx.pid #..возвращает управление немедленно, nginx master начал перечитывать настройки
if nginx -q -t; then
echo "В этот момент nginx master, скорее всего, уже работает с новыми настройками."
else
echo "В новых настройках ошибка, nginx master продолжил работать со старыми."
fi