Что такое ошибка ‘too many open files’ в Linux?

Ответ

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

Основные причины в DevOps-контексте:

  • Утечка дескрипторов: Сервис (например, веб-сервер или контейнер) не закрывает соединения или файлы после использования.
  • Недостаточный лимит: Лимиты по умолчанию (ulimit -n = 1024) малы для высоконагруженных приложений (базы данных, прокси, API-гейтвеи).
  • Растущая нагрузка: Внезапный всплеск трафика может исчерпать лимит.

Диагностика и решение:

  1. Найти проблемный процесс и проверить его лимиты:

    # Узнать PID процесса (например, nginx)
    pid=$(pgrep nginx | head -1)
    # Посмотреть текущее количество открытых дескрипторов
    ls -l /proc/$pid/fd | wc -l
    # Посмотреть лимиты для процесса
    cat /proc/$pid/limits | grep "open files"
  2. Повысить лимиты:

    • Временное решение для сессии: ulimit -n 65535
    • Постоянное решение через systemd (для сервиса):
      # /etc/systemd/system/your-service.service.d/limits.conf
      [Service]
      LimitNOFILE=65535
    • Глобальное решение для системы: Изменить /etc/security/limits.conf и перелогиниться.
  3. Проверить системный максимум:

    cat /proc/sys/fs/file-max
    # Если нужно увеличить (временно)
    sysctl -w fs.file-max=2097152

Профилактика: Мониторинг метрик open_fds и max_fds (например, в Prometheus через node_exporter) для ключевых сервисов.

Ответ 18+ 🔞

А, блядь, вот эта ошибка — EMFILE! Знакомо, да? Процессу говорят: «Открой файл», а он такой: «Не могу, руки закончились». В линуксе же всё — файл: сокеты, пайпы, реальные файлы — на всё нужен дескриптор, а их, сука, лимит.

Откуда эта хрень обычно лезет в продакшене:

  • Утечка, как из дырявого ведра: Сервис (ну, тот же nginx или какая-нибудь API-шняга) открыл соединение, отработал, а закрыть забыл — дескриптор болтается. И так по кругу, пока лимит не кончится. Распиздяйство, одним словом.
  • Лимиты дефолтные — просто смех: По умолчанию-то часто 1024. Это для современного сервиса, который тысячи соединений в секунду жуёт? Да он, блядь, за секунду упрётся! Особенно всякие базы или гейтвеи.
  • Внезапный пиздец (трафик): Ни с того ни с сего накатила волна запросов — и всё, приехали, лимит исчерпан. Ёпта.

Что делать, когда уже накрылось:

  1. Сначала ищем виноватого и смотрим, насколько ему тесно:

    # Находим PID процесса (допустим, nginx'а)
    pid=$(pgrep nginx | head -1)
    # Считаем, сколько файловых ручек он уже оторвал
    ls -l /proc/$pid/fd | wc -l
    # Смотрим, какой у него потолок по лимитам
    cat /proc/$pid/limits | grep "open files"

    Если число открытых дескрипторов впритык к лимиту — вот он, корень зла.

  2. Поднимаем потолок, чтобы не бился головой:

    • Быстро, на живую (чтоб не падало): ulimit -n 65535. Но это до перезагрузки.
    • Надежно, через systemd (чтоб навсегда запомнил):
      # Создаём файл /etc/systemd/system/your-service.service.d/limits.conf
      [Service]
      LimitNOFILE=65535

      Потом systemctl daemon-reload и перезапуск сервиса.

    • Всем сестрам по серьгам (глобально в системе): Ковыряем /etc/security/limits.conf, но тут надо перелогиниться или перезагрузиться — волнение ебать.
  3. Глянем, а не упёрлись ли мы в системный максимум вообще:

    cat /proc/sys/fs/file-max
    # Если мало, подкрутим (опять же, временно)
    sysctl -w fs.file-max=2097152

Чтобы не охуевать каждый раз: Поставь мониторинг на метрики open_fds и max_fds (через того же node_exporter в Prometheus). Увидишь, что график ползёт к потолку — уже знаешь, где ковырять. Предупреждён — значит, не обосрёшься в самый ответственный момент.