← Все статьи

SiteGuard12 мин чтения

Too many open files в Nginx: как проверить лимиты соединений и дескрипторов

Ошибка Too many open files в Nginx означает нехватку доступных файловых дескрипторов в определённом контексте. Дескрипторы нужны не только обычным файлам: ими пользуются сетевые соединения и служебные механизмы процесса. Поэтому сайт может перестать принимать запросы, хотя место на диске свободно, а процессор загружен умеренно.

Поиск «nginx too many open files» часто заканчивается увеличением нескольких чисел в конфигурации. Более надёжный путь — сначала определить вид ограничения, найти затронутый процесс и измерить расход ресурса. Затем выбирают изменение, проверяют новые воркеры и подтверждают работу сайта при сопоставимой нагрузке. Ниже — такой порядок для Nginx на Linux.

1. Различайте EMFILE, ENFILE и нехватку worker_connections

Сохраните точную строку журнала, время, PID процесса и действие, при котором возник отказ. Фрагмент (24: Too many open files) в типичном Linux-журнале соответствует EMFILE. В описании ошибок open он отделён от ENFILE: первый относится к пределу дескрипторов процесса, второй — к общесистемному пределу открытых файлов.

СигналЧто исчерпаноПервая проверка
EMFILE, Too many open filesДоступные дескрипторы конкретного процессаЛимиты и открытые fd затронутого PID
ENFILE, Too many open files in systemОбщесистемный ресурс открытых файловСостояние ядра и расход других процессов
worker_connections are not enoughВнутренний предел соединений рабочего процесса Nginxworker_connections и состав соединений воркера

Эти сообщения требуют разных решений. При исчерпании worker_connections операционная система ещё может разрешать открытие файлов. При EMFILE увеличение только внутреннего предела соединений не создаёт дополнительных дескрипторов. Не определяйте причину по слову «лимит»: привяжите конкретное сообщение к процессу и моменту нагрузки.

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

2. Найдите реальные master и worker процессы

Master управляет Nginx, а рабочие процессы обслуживают соединения. Не подставляйте PID master в каждую диагностическую команду автоматически: проблема конкретного воркера может отсутствовать у управляющего процесса. Сохраните PID из ошибки и сопоставьте его с текущим деревом процессов. После перезагрузки конфигурации этот PID может уже относиться к завершающемуся поколению.

Для ограниченного просмотра на своём сервере можно использовать следующий учебный пример. Команда только показывает процессы с указанным именем; её вывод изучают в закрытой административной сессии:

ps -C nginx -o pid,ppid,args

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

Запишите версию Nginx, путь используемой конфигурации и способ запуска. Это не повод публиковать полный конфигурационный дамп: для диагностики нужны только связанные настройки и структура экземпляра. Секреты из других виртуальных хостов и содержимое пользовательских запросов в отчёт не включают.

3. Прочитайте лимит и текущий расход у каждого воркера

Файл /proc/PID/limits показывает soft и hard limits конкретного процесса. Для этой задачи нужна строка Max open files. В примере число 12345 обозначает заранее найденный PID воркера, а не постоянный номер процесса:

rg '^Max open files' /proc/12345/limits
ls -1 /proc/12345/fd | wc -l

Вторая строка считает имена открытых дескрипторов. Согласно документации /proc/PID/fd, каталог содержит отдельные записи для дескрипторов, включая сокеты и каналы. Подсчёт даёт моментальный снимок, который может измениться уже во время чтения. Не интерпретируйте ошибку доступа или исчезновение PID как нулевой расход: сначала убедитесь, что команда действительно прочитала каталог.

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

Не открывайте содержимое дескрипторов и не меняйте права ради отчёта. Если для классификации нужны цели ссылок, ответственному администратору достаточно ограниченной выборки типов: сокеты, обычные файлы, каналы, служебные дескрипторы. Публичный список всех путей не требуется.

На управляемом хостинге эти измерения может выполнять поддержка. Передайте точное время, домен и ограниченный фрагмент ошибки, попросите указать PID, его действующий предел и расход во время отказа. Ответ «лимит на тарифе высокий» без связи с процессом не закрывает вопрос. Также уточните, обслуживает ли этот экземпляр соседние сайты: их нагрузка может объяснять расхождение с вашей статистикой посещений.

4. Почему ulimit в терминале не доказывает лимит Nginx

По правилам RLIMIT_NOFILE soft limit является действующим ограничением, а hard limit задаёт предел его повышения непривилегированным процессом. Для изменения hard limit нужны соответствующие полномочия; существует и ограничение ядра nr_open. Формально RLIMIT_NOFILE ограничивает доступный диапазон номеров дескрипторов, поэтому счётчик открытых fd используют вместе с фактическими лимитами.

Команда ulimit -n в административной оболочке описывает эту оболочку. Уже работающая служба от изменения в соседнем терминале не получает новые значения. Это ключевая ловушка запросов «ulimit nginx»: проверять нужно происхождение процессов и их собственные ограничения.

Если Nginx запускается через systemd, исходные лимиты задаются в контексте службы. Если его запускает контейнерная платформа или другой supervisor, проверяют соответствующий механизм. Универсальной связи «я изменил ulimit — сайт получил лимит» нет.

Сохраните оба числа из /proc/PID/limits, а не только наиболее большое. Высокий hard limit не доказывает высокий soft limit. И наоборот, наличие ограничения в файле службы не доказывает, что давно запущенный процесс уже работает с ним.

5. Сопоставьте LimitNOFILE и worker_rlimit_nofile

Параметр systemd LimitNOFILE задаёт ограничения для запускаемых процессов. Можно указать одно значение для обоих пределов либо пару soft:hard. Проверяйте эффективные параметры именно нужной службы с учётом её дополнительных настроек, а не только пакетный файл, поставленный при установке.

Директива Nginx worker_rlimit_nofile относится к рабочим процессам и размещается на основном уровне конфигурации. Возможность применить желаемое значение зависит от исходных ограничений, полномочий и ограничений ядра. Не представляйте взаимодействие настроек как безусловную формулу из двух чисел: окончательное доказательство — лимит реально созданного воркера и отсутствие ошибок его настройки.

Отдельно различайте перечитывание unit-файла и конфигурации приложения. В документации systemctl это разные действия: daemon-reload обновляет сведения менеджера служб, а reload обращается к самой службе. Перечитывание unit-файла само по себе не меняет ограничения уже работающего master.

Если для получения новых исходных лимитов необходим новый запуск службы, планируйте его отдельно с учётом доступности сайта. Не обещайте, что обычный graceful reload обязательно подхватит изменённый LimitNOFILE. Изменение worker_rlimit_nofile тоже проверяют по новым PID, а не по успешному сохранению файла.

6. Worker_connections — лимит соединений, а не посетителей

Документация основных директив Nginx определяет worker_connections как предел одновременных соединений одного рабочего процесса. Он включает соединения с проксируемыми серверами, а не только клиентские. Директива находится в блоке events; worker_rlimit_nofile управляет отдельным ресурсным ограничением воркеров.

Для обратного прокси один активный запрос может удерживать клиентское соединение и соединение к приложению. Но и правило «всегда делить на два» неверно: на соотношение влияют простаивающие соединения, повторное использование, протоколы и профиль работы. Открытое соединение не тождественно активному запросу.

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

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

7. Оставьте место для upstream, файлов и служебных операций

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

Отдельно проверьте простаивающие upstream-соединения. В описании upstream keepalive параметр относится к кешу неактивных соединений рабочего процесса и не ограничивает общее число соединений к приложению. Активные обращения и сохранённые соединения должны учитываться вместе. Не переносите предположения о значениях по умолчанию между версиями без проверки.

Если число воркеров увеличивают, пересчитайте совокупную нагрузку на backend и память. Несколько отдельных кешей соединений могут удерживать больше сокетов, чем один. Такое изменение способно убрать отказ Nginx и одновременно приблизить к пределу приложение, поэтому проверка заканчивается не на исчезновении строки из error log.

Запас выбирают по наблюдаемым пикам и предусмотренным операциям: выпуску, ротации журналов, изменению профиля запросов. Универсального безопасного процента для любого сайта нет. Зафиксируйте, какие категории включены в измерение, а какие покрывает резерв, чтобы расчёт можно было повторить.

8. Учебный расчёт для одного воркера

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

КатегорияКоличествоУчастие в расчёте
Клиентские соединения600Соединения и fd
Активные соединения к приложению500Соединения и fd
Неактивные upstream-соединения100Соединения и fd
Прочие открытые дескрипторы80Дополнительный расход fd

Основные сетевые соединения требуют 600 + 500 + 100 = 1200 мест. При worker_connections 1024 этот план уже не помещается, даже если лимит fd равен 2048. Поднять только worker_rlimit_nofile недостаточно.

С учётом остальных дескрипторов модель даёт 1200 + 80 = 1280 fd. Если рассматривать worker_connections 1536 и фактический лимит fd 2048, арифметические остатки составят 336 мест относительно основных соединений и 768 дескрипторов. Это два разных остатка; складывать их нельзя. Служебные соединения и неучтённые колебания также должны поместиться в соответствующий резерв.

Расчёт не подтверждает производительность: ещё нужны наблюдения за памятью, временем ответа и приложением. Он лишь показывает, почему проверяют несколько ограничений и почему один свободный ресурс не компенсирует другой. На своём сайте замените все условные числа измеренными значениями.

9. Выясните, почему расход растёт

Снимите несколько измерений до пика, во время него и после снижения нагрузки. Сопоставьте fd каждого воркера с активными соединениями, длительностью ответов upstream и количеством запросов. Если приложение отвечает медленнее, соединения могут дольше оставаться занятыми даже при прежнем входящем потоке.

Разделите ожидаемое удержание ресурсов и подозрение на утечку. Кеш соединений не обязан освобождаться мгновенно после прекращения запросов. Но устойчивый рост, который не объясняется нагрузкой и сохраняется после предусмотренных тайм-аутов, требует отдельного разбора. Сам график роста ещё не доказывает ошибку конкретного модуля.

Сравните состояние до и после последнего выпуска, подключения модуля или изменения keepalive. Посмотрите, какие категории fd выросли. Если увеличились сокеты к одному upstream, начните с его задержек и режима соединений. Если растёт число файлов, исследуйте связанные механизмы открытия и удержания. Не увеличивайте все тайм-ауты одновременно: это может дополнительно продлить занятие ресурса.

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

Для сравнения используйте одинаковый интервал и учитывайте состав запросов. Тысяча быстрых ответов из кеша и тысяча обращений к медленной интеграции создают разные условия удержания соединений. Отметьте долю долгих операций и время ответа зависимости. Это позволит выбрать между расширением обоснованно малого лимита и устранением причины, из-за которой ресурс стал освобождаться значительно медленнее.

10. При ENFILE проверьте систему целиком

Если подтверждён ENFILE, одного воркера недостаточно. В документации ядра Linux описаны file-max, file-nr и nr_open. Первые относятся к общесистемному учёту открытых файлов, а nr_open ограничивает допустимый предел процесса. Эти параметры нельзя подменять друг другом.

У file-nr три поля: выделенные файловые структуры, выделенные, но неиспользуемые, и максимум. В современных Linux второе поле обычно равно нулю по устройству учёта; само по себе это не означает исчерпание ресурса. Сопоставьте системное состояние с сообщениями ядра и расходом других служб.

Общесистемный счётчик не следует считать простой суммой каталогов /proc/PID/fd: дескрипторы и разделяемые открытые файловые структуры — разные уровни учёта. Не выводите из такого сложения «свободный остаток» сервера.

Если системный ресурс занимает другая служба, повышение лимита Nginx не устраняет источник. Решение принимают по общему потреблению и запасу памяти, с ответственным за затронутый компонент. Большое универсальное значение file-max без диагностики только отодвигает момент следующего отказа.

11. Меняйте настройки с проверкой новых процессов

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

worker_rlimit_nofile 2048;

events {
    worker_connections 1536;
}

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

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

Снова прочитайте /proc/PID/limits у новых воркеров и сравните расход fd. Учтите временное сосуществование поколений и связанные ресурсы. Не завершайте старые процессы принудительно только ради одинаковых чисел в списке: для долгих соединений действует отдельная процедура завершения.

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

12. Подтвердите доступность и устойчивый запас

Исправление принимают по наблюдаемому результату. Нужны подтверждённые лимиты новых процессов, отсутствие прежних отказов и успешные запросы в затронутом сценарии. Проверяйте также upstream: увеличение ёмкости Nginx не должно сопровождаться ростом очереди, ошибок приложения или времени ответа.

  1. Сверьте PID, поколение воркеров и фактические soft/hard limits.
  2. Проверьте индивидуальные пики fd и соединений при сопоставимом профиле.
  3. Убедитесь, что прежние сообщения не повторяются в новых журналах.
  4. Проверьте HTTP-ответ и прикладной результат контрольного запроса.
  5. Зафиксируйте изменённый источник настройки, расчёт запаса и условия пересмотра.

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

Подключите SiteGuard для внешнего контроля HTTP-доступности сайта. Лимиты Nginx и расход дескрипторов проверяет ваша команда.