Ответ
Основная причина — удалённый файл всё ещё удерживается открытым дескриптором работающего процесса. В Linux место на диске освобождается только после того, как все жёсткие ссылки на файл удалены и все открытые дескрипторы закрыты.
Типичные сценарии и решения:
-
Процесс держит файл открытым. Часто случается с демонами (nginx, app-server), которые пишут логи.
- Проверка:
lsof +L1илиlsof | grep deletedпокажет процессы и размер удалённых, но открытых файлов. - Решение: Отправить процессу сигнал для переоткрытия логов (например,
systemctl reload nginxилиkill -HUP <PID>). Полный перезапуст (restart) также решит проблему.
- Проверка:
-
Использование logrotate без copytruncate. По умолчанию
logrotateсоздаёт копию лога и просит процесс переоткрыть файл. Если процесс этого не делает (не поддерживает сигнал), старый дескриптор остаётся.- Решение: В конфигурации
logrotateдля проблемного сервиса используйте директивуcopytruncate. Она копирует файл, а затем обрезает оригинал до нуля, не требуя от процесса переоткрытия./var/log/myapp.log { daily rotate 7 copytruncate # Ключевая директива missingok }
- Решение: В конфигурации
-
Монтирование в пространство имён контейнера. Файл может быть удалён внутри контейнера, но оставаться открытым на хосте.
Порядок диагностики:
df -h— показывает «занятое» место, включая файлы с открытыми дескрипторами.du -sh /var/log/— показывает реальный размер файлов в директории. Еслиdfпоказывает много занятого, аdu— мало, это явный признак проблемы.lsof | grep deleted— найти виновника.- Принять меры (перезагрузка,
copytruncate, очистка диска от других файлов).
Ответ 18+ 🔞
А, ну это классика, ёпта! Ситуация, от которой у любого админа волосы дыбом встают: вроде файлы удалил, а место на диске как будто испарилось. Овердохуища занято, а куда — хрен поймёшь.
Короче, вся соль в том, что в Линуксе место освобождается только тогда, когда на файл вообще никто не ссылается. То есть все жёсткие ссылки удалены и все открытые дескрипторы закрыты. А если какой-то процесс этот файл не отпустил, то он физически на диске остаётся, хоть ты его из каталога и выкинул. Манда с ушами, а не ситуация.
Где обычно искать эту хитрожопую проблему и как её решать:
-
Процесс-невидимка. Чаще всего это какой-нибудь демон, который логи пишет, типа nginx или твоего app-server'а. Ты лог-файл удалил, а он своё держит за хвост старым дескриптором.
- Как найти виновника: Команда
lsof +L1илиlsof | grep deletedтебе всё покажет — кто держит, PID и какой размер у этого «призрака». - Что делать: Нужно заставить процесс отпустить старый файл и открыть новый. Часто хватает вежливого сигнала на переоткрытие логов:
systemctl reload nginxилиkill -HUP <PID>. Ну а если не понимает по-хорошему — полный перезапуск (restart) всегда работает, хоть это и тупой метод.
- Как найти виновника: Команда
-
Логротейт подвел. Вот тут, бля, тонкий момент. По умолчанию
logrotateделает копию лога, удаляет оригинал и просит процесс переоткрыть файл по сигналу. А если процесс — пидарас шерстяной и сигналы не ловит? Он так и будет писать в тот же удалённый файл своим старым дескриптором.- Решение — костыль, но рабочий: В конфиге
logrotateдля проблемного сервиса пропиши директивуcopytruncate. Она работает по-другому: сначала копирует файл, а потом обрезает оригинал до нуля. Процессу даже не нужно переоткрывать файл, он просто продолжает писать в тот же дескриптор, но файл уже пустой. Гениально и просто, как валенок./var/log/myapp.log { daily rotate 7 copytruncate # Вот эта волшебная палочка-выручалочка missingok }
- Решение — костыль, но рабочий: В конфиге
-
Контейнеры, ёб твою мать. Отдельная песня. Файл могли удалить внутри контейнера, а на хосте он всё ещё висит открытым. Тут уже надо смотреть и там, и там.
Так, а теперь по шагам, как не охуеть от неожиданности и найти, куда делось место:
df -h— показывает общую картину, включая эти самые «призрачные» файлы. Цифра будет пугать.du -sh /var/log/— а вот это показывает реальный размер того, что лежит в папке сейчас. Еслиdfкричит, что места нет, аduпоказывает, что всё чисто — поздравляю, ты нашёл проблему. Сам от себя охуел, да?lsof | grep deleted— финальный аккорд. Эта команда тычет пальцем прямо в морду процессу-вредителю. Смотри PID и размер.- Дальше уже действуй по обстановке: перезагрузи сервис, настрой
copytruncateили просто почисти другие файлы, если срочно нужно место. Главное — теперь-то ты знаешь, в чём дело.