ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

Лимиты дескрипторов: nofile, fs.inotify и rlimit для веб‑сервисов

Ошибки уровня «Too many open files» бьют по каждому продакшену, где трафик или число соединений растут быстрее, чем лимиты. Разбираем nofile, rlimit и fs.inotify: от диагностики и источников ограничений до практических пресетов для Nginx, PHP‑FPM, Node.js, MySQL и PostgreSQL.
Лимиты дескрипторов: nofile, fs.inotify и rlimit для веб‑сервисов

Если веб‑сервис работает под нагрузкой, рано или поздно вы встретите «Too many open files», «EMFILE», «ENFILE» или внезапные сбои вотчеров на файловой системе. Все эти симптомы упираются в лимиты дескрипторов и подсистему fs.inotify. В этой статье систематизируем, откуда берутся ограничения, как их измерить и безопасно поднять для Nginx, приложений (PHP‑FPM, Node.js) и баз данных (MySQL/MariaDB, PostgreSQL).

Что такое file descriptors и почему они заканчиваются

Дескрипторы файлов (file descriptors, FD) — это абстракция ядра для «открытых вещей»: файлы, сокеты, pipe, epoll, inotify и т. д. Каждый процесс имеет собственный предел открытых дескрипторов — это RLIMIT_NOFILE (часто называют просто nofile). Есть и системные пределы, например глобальный fs.file-max, регулирующий сколько дескрипторов ядро готово обслуживать одновременно.

Веб‑нагрузка быстро съедает FD: каждая входящая TCP‑сессия — это сокет; обратные прокси держат активные апстрим‑коннекты; базы данных открывают множество файлов таблиц и журналов; логгеры и метрики создают свои дескрипторы. Добавьте сюда вотчеры fs.inotify — и лимиты перестают быть «где‑то там» теоретическими.

Где живут лимиты: уровни и источники

  • Ядро: fs.file-max, /proc/sys/fs/nr_open, fs.inotify.* (ниже разберём).
  • Per‑process: RLIMIT_NOFILE — лимит «открытых файлов» на процесс.
  • Запуск через systemd: директива LimitNOFILE= в unit‑файле.
  • Shell‑сессия: ulimit -n (работает для текущего процесса и его потомков).
  • PAM limits: /etc/security/limits.conf и limits.d для интерактивных логинов, если включён pam_limits.
  • Настройки самих приложений: Nginx worker_rlimit_nofile, PHP‑FPM rlimit_files, MySQL open_files_limit и т. п.

Ключевая особенность: сервисы, запущенные через systemd, не читают /etc/security/limits.conf. Для них источником истины является unit: LimitNOFILE= и глобальные DefaultLimit* из /etc/systemd/system.conf (лучше настраивать per‑service).

На обычном хостинге провайдер задаёт лимиты. Полный контроль над sysctl и unit‑файлами вы получаете на своём VDS.

Иллюстрация лимитов fs.inotify: watches, instances и очередь событий

Быстрая диагностика текущих лимитов

Проверьте лимит в текущей shell:

ulimit -n

Посмотрите фактические лимиты конкретного процесса (пример для Nginx master):

cat /proc/$(pgrep -o nginx)/limits

Глобальные значения ядра:

cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open
sysctl fs.inotify.max_user_watches fs.inotify.max_user_instances fs.inotify.max_queued_events

Сколько дескрипторов реально занято у процесса:

lsof -nP -p $(pgrep -o nginx) | wc -l

Краткая сводка по сокетам:

ss -s

Если Nginx пишет «accept4: Too many open files» — почти наверняка не хватает RLIMIT_NOFILE для воркеров. Если MySQL жалуется на открытие таблиц — проверьте open_files_limit и лимиты systemd для службы СУБД.

fs.inotify: когда утыкается наблюдение за файлами

Inotify позволяет процессам подписываться на события файловой системы. Большинство «вотчеров» (деплой‑демоны, агенты логов, сборщики метрик, билд‑инструменты) используют именно его. Лимиты:

  • fs.inotify.max_user_watches — сколько «наблюдений» на пользователя.
  • fs.inotify.max_user_instances — сколько inotify‑инстансов на пользователя.
  • fs.inotify.max_queued_events — глубина очереди событий.

Симптомы ухода в лимиты: отвалившиеся вотчеры, «No space left on device» при попытке добавить новое наблюдение, повышенные задержки обработки изменений.

План действий: как безопасно поднять лимиты

  1. Измерьте текущее потребление FD и inotify‑вотчей у процессов.
  2. Задайте целевой запас исходя из пиковых нагрузок + 30–50% headroom.
  3. Поднимите системные лимиты через sysctl и перезапустите сервисы с обновлённым LimitNOFILE.
  4. Проверьте логи на отсутствие ошибок и повторно снимите метрики использования FD.

Коротко: в 80% случаев достаточно поднять fs.file-max, LimitNOFILE у systemd‑юнитов и, при необходимости, fs.inotify.max_user_watches. Не забывайте, что настройки в конфиге приложения могут дополнительно ограничивать открытые файлы.

Настройка на уровне ядра (sysctl)

Создайте отдельный файл с параметрами, чтобы не трогать sysctl.conf напрямую:

# /etc/sysctl.d/99-fd-inotify.conf
fs.file-max = 1000000
fs.inotify.max_user_watches = 1048576
fs.inotify.max_user_instances = 1024
fs.inotify.max_queued_events = 32768

Примените изменения:

sysctl --system

Пояснения:

  • fs.file-max — общий «пул» дескрипторов. Значение 1M подходит большинству средних инсталляций; для нагруженных систем используйте миллионы, ориентируясь на RAM.
  • Каждый inotify‑watch потребляет память (сотни байт плюс накладные расходы). Миллионы вотчей — это гигабайты RAM. Не завышайте без нужды.

systemd: лимиты per‑service

Для сервиса, например Nginx:

systemctl edit nginx

И добавьте в открывшийся drop‑in:

[Service]
LimitNOFILE=200000

Перечитайте конфигурацию и перезапустите:

systemctl daemon-reload
systemctl restart nginx

Проверьте фактический лимит у процесса:

cat /proc/$(pgrep -o nginx)/limits | grep -i open

Если нужно глобально поднять дефолт для всех будущих unit‑файлов, используйте /etc/systemd/system.conf с DefaultLimitNOFILE=, но лучше контролировать на уровне каждого сервиса.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Nginx: связь nofile, worker_connections и ошибки

Nginx ограничен не только RLIMIT_NOFILE, но и собственными настройками:

  • events.worker_connections — максимальные соединения на воркер.
  • worker_processes — число воркеров.
  • worker_rlimit_nofile — значение для RLIMIT_NOFILE worker‑процессов (независимо от лимита мастера).

Типовой фрагмент для нагруженного инстанса:

worker_processes auto;
worker_rlimit_nofile 200000;

events {
    worker_connections 65535;
    multi_accept on;
}

Правило большого пальца: потенциальное число одновременно открытых сокетов у Nginx примерно равно worker_processes × worker_connections плюс внутренние файлы и лог‑дескрипторы. Делайте запас в worker_rlimit_nofile и в LimitNOFILE systemd‑юнита.

Ошибки вида «accept4: Too many open files» или 502/504 под нагрузкой часто исчезают после корректного увеличения лимитов и настройки keepalive на апстримах.

Связь worker_connections, worker_processes и nofile для Nginx

PHP‑FPM и Node.js

PHP‑FPM

Два места, где упираетесь в лимиты:

  • Лимит systemd у службы php‑fpm.
  • Опциональный параметр пула rlimit_files.

Пример drop‑in для systemd:

[Service]
LimitNOFILE=131072

В пуле FPM (например, /etc/php/8.2/fpm/pool.d/www.conf):

rlimit_files = 131072

После правок перезапустите FPM и убедитесь, что в /proc/<pid>/limits видите увеличенные значения.

Node.js

Node‑приложения часто падают в EMFILE при массовых операциях с сокетами или при запущенных вотчерах. Для сервисов под systemd достаточно поднять LimitNOFILE; для локальных дев‑окружений — ulimit -n. Если используете менеджер процессов (PM2, systemd), контролируйте лимиты там, где стартует процесс.

Базы данных: MySQL/MariaDB и PostgreSQL

MySQL/MariaDB

Ограничения на открытые файлы регулируются параметром open_files_limit и связаны с table_open_cache. Но верхняя планка — это всё равно RLIMIT_NOFILE процесса СУБД. Последовательность:

  1. Поднимите LimitNOFILE в unit‑файле службы MySQL/MariaDB.
  2. В my.cnf задайте целевое open_files_limit и соответствующий table_open_cache.
  3. Перезапустите службу и проверьте значения через SHOW VARIABLES.
# /etc/mysql/my.cnf
[mysqld]
open_files_limit = 200000
table_open_cache = 8192

Проверка:

mysql -e "SHOW VARIABLES LIKE 'open_files_limit';"

Симптомы нехватки: «Can't open file», частые закрытия/открытия таблиц, рост latency на запросах из‑за постоянного вращения дескрипторов.

PostgreSQL

Postgres читает RLIMIT_NOFILE от системы и сам не имеет отдельного параметра для «open files». Действуйте через systemd:

[Service]
LimitNOFILE=131072

Важно помнить, что дескрипторы потребляют не только backend‑процессы коннектов, но и чекпойнты, автовакуум и расширения. Учитывайте суммарное число процессов и возможные пики коннектов.

Если вы шифруете соединения СУБД, отдельно проверьте TLS‑настройки и цепочки сертификатов — это тоже дескрипторы на сокеты и ключи. Подробности см. в разборе TLS для MySQL и PostgreSQL: CA и настройки.

Ошибки и лог‑сообщения: что искать

  • Nginx: «accept() failed (24: Too many open files)», «upstream prematurely closed connection».
  • PHP‑FPM: «failed to open error_log», «Too many open files» при форках воркеров.
  • Node.js: «EMFILE: too many open files, watch».
  • MySQL/MariaDB: «Can't open file», «Too many open files» при пиках.
  • PostgreSQL: «too many open files in system», «could not open file».
  • Inotify: «No space left on device» при добавлении watch.

Проверяем фактическое потребление и запас

Снимите срез во время пика:

PID=$(pgrep -o nginx)
lsof -nP -p $PID | wc -l
cat /proc/$PID/limits | grep -i open

Подготовьте отчёт: текущий максимум FD, пиковое значение, целевой запас, какие юниты и sysctl были изменены. Это поможет в change‑management и при последующих аудитах.

Память и безопасность: не задирайте бесконечно

Каждый дескриптор и inotify‑watch потребляют память ядра. Миллионы FD в системе без реальной потребности — это лишняя RAM и потенциально более сложные таблицы поиска, что может влиять на латентность в крайних случаях. Для продакшена используйте здравый запас и мониторинг.

  • Добавьте алерты по занятости FD на процесс и по системе (экспорт из /proc/sys/fs/file-nr и /proc/<pid>/fd).
  • Лимиты повышайте итеративно и только после измерений.

В тему оптимизации памяти на серверах приложений и баз данных посмотрите нашу статью про оптимизацию THP и HugePages для PHP и баз данных.

PAM limits и интерактивные сессии

Если админ‑скрипты или демоны запускаются из crontab или вручную через shell, убедитесь, что pam_limits включён, а в limits.conf задан разумный nofile для нужных пользователей или групп. Но помните: для systemd‑сервисов это не работает — им настраиваем LimitNOFILE в unit‑файлах.

Контейнерные окружения (кратко)

В контейнерах лимиты по умолчанию часто ниже. Управляйте ими на уровне рантайма (параметры ulimit) и внутри гостевой ОС, если там запускается systemd. Также обращайте внимание на передачу sysctl‑параметров ядра — не все можно менять изнутри контейнера.

Чек‑лист внедрения

  1. Соберите метрики: пиковые FD и inotify‑watch per process, по системе.
  2. Повысьте fs.file-max и fs.inotify.* через /etc/sysctl.d/, примените sysctl --system.
  3. Задайте LimitNOFILE в drop‑in для каждого сервиса: Nginx, PHP‑FPM, Node.js, базы данных.
  4. Для Nginx настройте worker_rlimit_nofile и worker_connections с запасом.
  5. Для MySQL/MariaDB проверьте open_files_limit и table_open_cache; для PostgreSQL — только systemd‑лимит.
  6. Перезапустите сервисы, подтвердите новые лимиты через /proc/<pid>/limits.
  7. Включите мониторинг и алерты по занятости FD и очередям inotify.

Итоги

Лимиты дескрипторов — это не «тайная магия», а три слоя: ядро (sysctl), менеджер служб (systemd) и конкретные приложения. Понимание того, где именно вы упираетесь — в RLIMIT_NOFILE, в worker_connections, в open_files_limit или в fs.inotify — позволяет быстро устранить «Too many open files», стабилизировать Nginx и приложения, а также избежать скрытых деградаций баз данных. Настраивайте лимиты осознанно, подтверждайте их метриками и оставляйте разумный запас.

Поделиться статьей

Вам будет интересно

HTTP‑лимиты в Nginx: client_max_body_size и тело запроса для PHP и API OpenAI Статья написана AI (GPT 5)

HTTP‑лимиты в Nginx: client_max_body_size и тело запроса для PHP и API

Почему Nginx внезапно отвечает 413, 400 или зависает на загрузке файлов? Часто причина в лимитах тела HTTP‑запроса: client_max_bod ...
Лимиты ресурсов на VDS: ulimit, sysctl и настройка для веб‑проектов OpenAI Статья написана AI (GPT 5)

Лимиты ресурсов на VDS: ulimit, sysctl и настройка для веб‑проектов

На новом VDS всё обычно летает, пока сайт не вырастет и не упрётся в скрытые лимиты: открытые файлы, процессы, сокеты, память. Раз ...
PHP uploads: настройка загрузки файлов и медиа на Nginx и Apache OpenAI Статья написана AI (GPT 5)

PHP uploads: настройка загрузки файлов и медиа на Nginx и Apache

Разбираем, как в PHP устроена загрузка файлов: временные файлы, лимиты размера и времени, ключевые параметры в php.ini, влияние на ...