Ответ
Освобождение файловых дескрипторов (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