Небольшая заметка по одной из ошибок nginx, с которой вы можете столкнуться по мере роста нагрузки на web сервер. Исправляется она легко, но я оставлю небольшие комментарии по ней, чтобы было понимание причины.
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном онлайн-курcе по администрированию MikroTik. Автор курcа – сертифицированный тренер MikroTik Дмитрий Скоромнов. Более 40 лабораторных работ по которым дается обратная связь. В три раза больше информации, чем в MTCNA.
Полностью эта ошибка будет выглядеть примерно так:
[alert] 24315#24315: *380953159 socket() failed (24: Too many open files) while connecting to upstream
К этой ошибке приводит системное ограничение на количество открытых файлов для рабочего процесса. Посмотреть это ограничение можно простой командой в консоли.
# ulimit -n 1024
Она равна 1024. Можно изменить системные лимиты, но есть более простое и разумное решение. Нет смысла менять системный лимит, если нас интересуют только процессы nginx. Для изменения лимита только для них, если отдельный параметр в конфигурации nginx - worker_rlimit_nofile (ссылка на официальную документацию).
Остается один вопрос - какое значение туда поставить. Я нашел информацию, что на каждое соединение nginx открываются два файловых дескриптора - один на соединение, один непосредственно на открытие файла. Я не смог найти подтверждения, но даже если эта информация не верна, ничего страшного не будет, если мы каждому соединению оставим 2 файловых дескриптора.
Теперь рассчитаем, какое значение в параметре worker_rlimit_nofile нам надо установить. Допустим, у нас есть 4-х ядерный сервер с такими параметрами nginx:
worker_processes auto; events { worker_connections 5120; }
В данном случае у нас количество запущенных процессов будет автоматически равно количеству ядер. А на один процесс разрешено 5120 соединений. Таким образом, суммарно у нас может быть 5120 * 4 = 20480 соединений. На каждое соединение нужно 2 файловых дескриптора. Значит параметр worker_rlimit_nofile должен быть равен 40960:
worker_rlimit_nofile 40960;
После изменения достаточно просто перечитать конфигурацию.
# nginx -s reload
Проверить, применились ли новые лимиты на процессы nginx можно, выполнив следующую команду в консоли:
for pid in `pidof nginx`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done
Все в порядке, системный лимит остался дефолтным, а для процессов nginx изменился. Более подробно о том, как настроить nginx читайте в отдельной большой статье с примерами.
На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
2023, RockyLinux 8, метод работает
Данный вариант уже не актуален и не меняется.
Данное значение теперь меняется через systemctl
# vi /etc/sysctl.conf
fs.file-max = 64000
Edit /etc/security/limits.conf and add:
nginx soft nofile 64000
nginx hard nofile 64000
echo 'NGINX_ULIMIT="-n 64000"' >> /etc/sysconfig/nginx
Edit /usr/lib/systemd/system/nginx.service and add a line in the [Service] section:
LimitNOFILE=64000
In /etc/sysconfig/nginx.systemd add:
LimitNOFILE=64000
Reload system daemon:
# systemctl --system daemon-reload
# sysctl -p
Restart nginx:
# /etc/init.d/nginx restart
Почему не актуален? Через systemctl или системные лимиты напрямую и раньше можно было поменять. Это не принципиально. Вы проверяли предложеннный мной вариант и он не сработал?
Верно. Я проверил.
И я сталкиваюсь с данной проблемой очень часто.
Попробуйте на centos или ubuntu ваш вариант и проверьте реальный кейс :)
Вы похоже не не помните, когда из за нового патча ядра, ограничения sysctl, ломали mysql открытие множества файлов, из за чего mysql работал так же не корректно.
Сейчас не service управляет процессом, а systemd.
Из за чего ваш вариант подходит только для старых систем, где основной процесс запуска был через init.d
И сейчас всё работает.
nginx -s reload
может только не отрабатывать из-за того что в официальном репо в nginx.conf есть строка
pid /run/nginx.pid;
А в файле /usr/lib/systemd/system/nginx.service
PIDFile=/var/run/nginx.pid
Из-за этого nginx -s reload естественно выдаёт
nginx: [error] invalid PID number "" in "/run/nginx.pid"
Нужно просто в nginx.conf строку заменить на
pid /var/run/nginx.pid;
И всё заработает и лимиты по nginx -s reload применяются (проверил на CentOS / RHEL 7)
Работает, спасибо! А пример в статье у меня не заработал.