Диск наполовину пуст, а файл не создаётся. Показываем, как заканчиваются inode, как это увидеть командой df -i и очистить.
Приложение падает с ошибкой «No space left on device», а df -h честно показывает, что диск занят на 3%. Не сломан ни диск, ни команда: на диске закончились не байты, а inode. Разберём, что это такое, как это увидеть за одну команду и как очистить сервер, ничего не сломав.
Коротко. inode - запись о файле в файловой системе: один файл или каталог занимает один inode, независимо от размера. Их число ограничено. Проверка:
df -i, колонкаIUse%. Найти виновника:sudo du --inodes -x -d1 /var | sort -rn | head. Очистить:find КАТАЛОГ -type f -delete. Причина почти всегда одна: миллионы мелких файлов (сессии, кэш, очередь почты).
Представьте библиотеку: книг может быть мало, но каждой нужна карточка в каталоге. Если карточки кончились, новую книгу не принять, хотя полки пусты. Так и здесь: в inode хранятся владелец, права и положение данных файла, а само содержимое лежит отдельно. Файл на 1 байт и файл на 1 ГБ занимают по одному inode.
В файловой системе ext4, которая стоит на большинстве серверов, число inode задаётся при её создании. Обычно оно считается из размера диска - примерно один inode на 16 КиБ, - то есть на обычной нагрузке хватает с запасом. Но если приложение плодит миллионы крошечных файлов, лимит выбирается раньше, чем место.
Чтобы показать симптом без поломки настоящего диска, мы создали временный диск в памяти (tmpfs) на 64 МБ и сами ограничили его двумя тысячами inode. Это имитация: у реального ext4 лимит задаётся при создании, мы просто выставили его вручную. Так сервер выглядит до проблемы:
df -h считает байты, df -i - inode. Это две разные шкалы, и вторую почти никто не смотрит, пока не случится беда. Теперь заполним диск пустыми файлами, как это делает приложение, которое не чистит за собой временные файлы. Создалось 1998 штук. Следующий файл не создаётся:
Теперь смотрим на диск в обоих режимах:
В колонке Avail по-прежнему 64 МБ, а в колонке IFree ноль. Это и есть главный признак: df -h пустой, df -i на 100%. Нет смысла искать большие файлы - они не виноваты.
Нужно понять, где лежит множество мелких файлов. Для этого у du есть ключ --inodes: он считает не размер, а число объектов. Остальные ключи: -x - не заходить на другие файловые системы, -d1 - глубина один уровень. sort -rn ставит самые большие числа первыми, head оставляет начало списка. Проверяем нужную точку монтирования (на реальном сервере обычно /, /var или /home):
Первая строка - итог по каталогу, а вторая показывает, кто съел почти всё: каталог sessions. Дальше спускаемся ниже тем же способом, пока не найдём конкретное место. На боевых серверах чаще всего это каталоги сессий PHP, кэш приложения, очередь почты /var/spool и временные файлы в /tmp.
Прежде чем удалять, убедитесь, что файлы действительно временные: посмотрите, что за приложение их создаёт, и какие из них можно стереть. Если сомневаетесь - сначала переместите или заархивируйте.
Для миллионов файлов команда rm КАТАЛОГ/* не подходит: оболочка раскрывает звёздочку в огромный список, и rm отвечает ошибкой «Argument list too long». Вместо этого find сам обходит каталог и удаляет файлы по одному:
find /mnt/inode-demo/sessions -xdev -type f -name 'sess_1*' -deleteРазберём ключи. -xdev - не выходить за пределы одной файловой системы. -type f - только обычные файлы, каталоги не трогаем. -name 'sess_1*' - только файлы, имя которых начинается с sess_1 (в бою здесь может стоять, например, -mtime +7: старше семи дней). -delete - удалить найденное. Если сомневаетесь, сначала запустите команду без -delete: она просто покажет, что нашла.
Занято 45%, файлы создаются, ошибка ушла (0 - команда выполнилась успешно). Мы удалили только часть - и этого хватило. После этого нужно ещё вылечить причину, иначе через неделю всё повторится.
find /var/tmp -type f -mtime +7 -delete раз в сутки через cron.IUse% так же, как за местом. Достаточно команды df -i в вашей проверке состояния сервера.Если при нехватке места сервер ещё и тормозит, смотрите разбор «Сервер тормозит», а за памятью следите по статье про OOM killer.
Скорее всего, закончились inode. Запустите df -i: если IUse% равен 100%, дело в них. Если и там порядок, смотрите квоты и тома, но в первую очередь проверяйте inode.
Запись о файле или каталоге: владелец, права и где лежат данные. Один файл - один inode, независимо от размера.
Командой sudo du --inodes -x -d1 /var | sort -rn | head. Повторяйте её для найденного каталога, спускаясь вглубь, пока не найдёте источник.
Через find КАТАЛОГ -type f -delete. Обычный rm * на таком объёме ответит «Argument list too long».
df -i, смотрим IUse%.sudo du --inodes -x -d1 /var | sort -rn | head.find КАТАЛОГ -type f -delete, а не rm *; сначала запускаем без -delete.df -i в регулярной проверке.