Ответ
Команда df (disk free) показывает статистику на уровне файловой системы, а не на уровне открытых файловых дескрипторов. Место не освобождается для файловой системы до тех пор, пока на файл не перестанут ссылаться все дескрипторы.
Техническая причина: В Unix/Linux файл существует, пока на него есть хотя бы одна жесткая ссылка (hard link). Команда rm удаляет лишь одну ссылку (имя файла в директории). Если какой-либо процесс в момент удаления держал файл открытым, ядро сохраняет связь через дескриптор, и данные на диске продолжают занимать место. Файл становится "удаленным" (не виден в ls), но место будет занято до закрытия дескриптора.
Типичные сценарии в DevOps:
- Лог-файлы приложения: Процесс пишет в
app.log. Администратор удаляет файл (rm app.log), чтобы освободить место, но процесс продолжает писать через открытый дескриптор. Место не освобождается, а новый файлapp.logне создается. Решение: использоватьlogrotateс сигналом на переоткрытие файлов (например,copytruncateилиpostrotateсkill -HUP). - Временные файлы: Скрипт создает и открывает временный файл, но не закрывает его перед удалением.
Диагностика и решение:
# 1. Найти процессы, держащие удаленные файлы открытыми
$ lsof +L1 | grep -i deleted
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
java 1234 app 5w REG 8,16 2.1G 0 12345 /var/log/app.log (deleted)
# 2. Освободить место можно одним из способов:
# - Перезапустить процесс (PID 1234): `systemctl restart app.service`
# - Вручную очистить файл через дескриптор (если это безопасно):
$ : > /proc/1234/fd/5
# 3. Правильное управление логами через logrotate
# /etc/logrotate.d/app
/var/log/app.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 644 app app
postrotate
# Сигнал процессу переоткрыть лог-файл
kill -HUP `cat /var/run/app.pid 2>/dev/null` 2>/dev/null || true
endscript
}
Вывод df обновится только после того, как все дескрипторы на удаленный файл будут закрыты.