Nginx - Too many open files

Небольшая заметка по одной из ошибок nginx, с которой вы можете столкнуться по мере роста нагрузки на web сервер. Исправляется она легко, но я оставлю небольшие комментарии по ней, чтобы было понимание причины.

Углубленный онлайн-курс по MikroTik

Научиться настраивать 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 - Too many open files

Все в порядке, системный лимит остался дефолтным, а для процессов nginx изменился. Более подробно о том, как настроить nginx читайте в отдельной большой статье с примерами.

Онлайн-курс по устройству компьютерных сетей.

На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
Не понравилась статья и хочешь научить меня администрировать? Пожалуйста, я люблю учиться. Комментарии в твоем распоряжении. Расскажи, как сделать правильно!

Помогла статья? Подписывайся на telegram канал автора

Анонсы всех статей, плюс много другой полезной и интересной информации, которая не попадает на сайт.

Автор Zerox

Владимир, системный администратор, автор сайта. Люблю настраивать сервера, изучать что-то новое, делиться знаниями, писать интересные и полезные статьи. Открыт к диалогу и сотрудничеству. Если вам интересно узнать обо мне побольше, то можете послушать интервью. Запись на моем канале - https://t.me/srv_admin/425 или на сайте в контактах.

8 комментариев

  1. 2023, RockyLinux 8, метод работает

  2. Данный вариант уже не актуален и не меняется.
    Данное значение теперь меняется через 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)

    • Работает, спасибо! А пример в статье у меня не заработал.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить комментарий" Я даю согласие на обработку персональных данных.
Используешь Telegram? Подпишись на канал автора →
This is default text for notification bar