Ответ
Освобождение файловых дескрипторов (FD) — частая задача при устранении проблем с "Too many open files". Вот методы, которые применяю в зависимости от ситуации.
1. Диагностика (поиск виновника):
# Нахожу PID процесса с большим количеством открытых FD
lsof | awk '{print $2}' | sort | uniq -c | sort -rn | head
# Или для конкретного процесса
ls -la /proc/<PID>/fd | wc -l
# Смотрю, какие именно файлы открыты процессом
lsof -p <PID>
# Или ищу процесс, блокирующий конкретный файл
lsof /path/to/locked/file
2. Методы освобождения дескрипторов:
А. Корректное завершение процесса (предпочтительно):
# Отправляю SIGTERM для graceful shutdown
kill <PID>
# Если не срабатывает, через 30 секунд отправляю SIGKILL
kill -9 <PID>
Б. Принудительное освобождение файла с помощью fuser:
# Показываю процессы, использующие файл
fuser -v /path/to/file
# Принудительно завершаю все процессы, использующие файл
fuser -k /path/to/file
# Для TCP/UDP портов (например, если процесс не отпускает сокет)
fuser -k 8080/tcp
В. Закрытие конкретного дескриптора в работающем процессе (осторожно!):
# Использую gdb для вызова close() на конкретном FD
# Например, чтобы закрыть FD 42 в процессе 12345
gdb -p 12345 -ex "call close(42)" -ex "detach" -ex "quit"
Важно: Этот метод может привести к нестабильности процесса, если дескриптор активно используется.
Г. Перезапуск сервиса через systemd:
# Для systemd-сервисов
sudo systemctl restart nginx.service
# Или с принудительным завершением
sudo systemctl kill -s KILL nginx.service
3. Практический пример из инцидента: При обработке инцидента с исчерпанием лимита файловых дескрипторов у Nginx в production:
# 1. Нашел PID основного процесса nginx
cat /var/run/nginx.pid
# 2. Посчитал открытые FD (их было > 8000 при лимите 8192)
ls -1 /proc/$(cat /var/run/nginx.pid)/fd | wc -l
# 3. Увидел, что многие FD указывают на лог-файлы
lsof -p $(cat /var/run/nginx.pid) | grep ".log$"
# 4. Принял решение о ротации логов и graceful reload
sudo logrotate -f /etc/logrotate.d/nginx
sudo nginx -s reload # Отправляет SIGHUP, заставляет nginx переоткрыть лог-файлы
# 5. Проверил результат
ls -1 /proc/$(cat /var/run/nginx.pid)/fd | wc -l # Стало ~50
4. Профилактика:
# Увеличиваю системные лимиты
echo "fs.file-max = 65536" >> /etc/sysctl.conf
sysctl -p
# Увеличиваю лимиты для конкретного пользователя/процесса
ulimit -n 65536
# В systemd-сервисе добавляю в .service файл
[Service]
LimitNOFILE=65536 Ответ 18+ 🔞
Ах ты ж ёпта, ну вот опять эта хуйня с файловыми дескрипторами! «Too many open files», блядь, классика жанра. Сидишь такой, а тут тебе — овердохуища файлов открыто, и всё, приехали. Ладно, слушай сюда, как я с этим обычно воюю.
1. Сначала ищем, кто виноват (диагностика, ёб твою мать):
# Ищу, у какого процесса больше всего открытых FD, чтобы знать, кого ебашить
lsof | awk '{print $2}' | sort | uniq -c | sort -rn | head
# Или для конкретного подозреваемого смотрю, сколько у него этих дескрипторов
ls -la /proc/<PID>/fd | wc -l
# А потом разбираюсь, что это за файлы такие интересные
lsof -p <PID>
# Или если конкретный файл не даёт покоя — ищу, кто его держит
lsof /path/to/locked/file
2. Методы, как освободить эту всю пиздопроебибну:
А. Нормально завершить процесс (самый правильный путь, если можно):
# Вежливо прошу закрыться (SIGTERM)
kill <PID>
# Если через 30 секунд он ещё живёт — тут уже извини, дружок, получай SIGKILL
kill -9 <PID>
Б. Принудительно освободить файл через fuser (когда нужно быстро):
# Смотрю, какие процессы прилипли к файлу
fuser -v /path/to/file
# А потом просто выношу всех, кто его использует
fuser -k /path/to/file
# То же самое для портов, если сокет не отпускает
fuser -k 8080/tcp
В. Закрыть конкретный дескриптор прямо в работающем процессе (осторожно, тут волнение ебать!):
# Использую gdb, чтобы вызвать close() на конкретном FD
# Например, закрываю FD 42 в процессе 12345
gdb -p 12345 -ex "call close(42)" -ex "detach" -ex "quit"
Важно: Этот способ — чистая рулетка. Если процесс в этот момент этим дескриптором пользуется, будет тебе хиросима, процесс может просто накрыться медным тазом.
Г. Перезапустить сервис через systemd (проще всего, если это сервис):
# Для systemd-сервисов
sudo systemctl restart nginx.service
# Или сразу жёстко, если не реагирует
sudo systemctl kill -s KILL nginx.service
3. Практический пример из жизни, когда у меня Nginx в проде обосрался: Было дело, лимит FD подошёл к концу. Делал вот так:
# 1. Нашёл PID основного процесса nginx
cat /var/run/nginx.pid
# 2. Посчитал открытые FD (их было больше 8000, а лимит 8192 — уже паника)
ls -1 /proc/$(cat /var/run/nginx.pid)/fd | wc -l
# 3. Увидел, что куча FD висит на лог-файлах — ну ясное дело, логи не ротировались
lsof -p $(cat /var/run/nginx.pid) | grep ".log$"
# 4. Принял решение: ротация логов и graceful reload
sudo logrotate -f /etc/logrotate.d/nginx
sudo nginx -s reload # Отправляю SIGHUP, nginx переоткрывает лог-файлы
# 5. Проверил — стало около 50 FD, а не 8000. Удивление пиздец!
ls -1 /proc/$(cat /var/run/nginx.pid)/fd | wc -l
4. Профилактика, чтобы потом не бздеть:
# Поднимаю системный лимит
echo "fs.file-max = 65536" >> /etc/sysctl.conf
sysctl -p
# Поднимаю лимит для пользователя/процесса
ulimit -n 65536
# Для systemd-сервиса прописываю в .service файл
[Service]
LimitNOFILE=65536
Вот так вот, чувак. Главное — не паниковать, когда видишь эту ошибку. Почти всегда находится какая-нибудь хитрая жопа в виде незакрытых логов или сокетов. Находишь — и ебёшь.