Небольшая заметка по одной из ошибок nginx, с которой вы можете столкнуться по мере роста нагрузки на web сервер. Исправляется она легко, но я оставлю небольшие комментарии по ней, чтобы было понимание причины.
Полностью эта ошибка будет выглядеть примерно так:
1 |
[alert] 24315#24315: *380953159 socket() failed (24: Too many open files) while connecting to upstream |
К этой ошибке приводит системное ограничение на количество открытых файлов для рабочего процесса. Посмотреть это ограничение можно простой командой в консоли.
1 2 |
ulimit -n 1024 |
Она равна 1024. Можно изменить системные лимиты, но есть более простое и разумное решение. Нет смысла менять системный лимит, если нас интересуют только процессы nginx. Для изменения лимита только для них, если отдельный параметр в конфигурации nginx – worker_rlimit_nofile.
Остается один вопрос — какое значение туда поставить. Я нашел информацию, что на каждое соединение nginx открываются два файловых дескриптора — один на соединение, один непосредственно на открытие файла. Я не смог найти подтверждения, но даже если эта информация не верна, ничего страшного не будет, если мы каждому соединению оставим 2 файловых дескриптора.
Теперь рассчитаем, какое значение в параметре worker_rlimit_nofile нам надо установить. Допустим, у нас есть 4-х ядерный сервер с такими параметрами nginx:
1 2 3 4 |
worker_processes auto; events { worker_connections 5120; } |
В данном случае у нас количество запущенных процессов будет автоматически равно количеству ядер. А на один процесс разрешено 5120 соединений. Таким образом, суммарно у нас может быть 5120 * 4 = 20480 соединений. На каждое соединение нужно 2 файловых дескриптора. Значит параметр worker_rlimit_nofile должен быть равен 40960:
1 |
worker_rlimit_nofile 40960; |
После изменения достаточно просто перечитать конфигурацию.
1 |
nginx -s reload |
Проверить, применились ли новые лимиты на процессы nginx можно, выполнив следующую команду в консоли:
1 |
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 изменился.