Файлов на диске меньше, чем показывает занятого места

Майор

Администратор
Команда форума
Регистрация
04.09.14
Сообщения
2.837
Реакции
1.942
Баллы
113
Нередко случается такое, что приложение говорит «cannot write blah to hdd, not enough space», хотя df -h говорит, что места ещё дохрена. Неопытный админ начинает задумчиво чесать репу, удивляться, гуглить и тд.
Чаще всего такое поведение случается в трех случаях:
0) вы не туда смотрите df-ом
1) кончились inodes на диске
2) какой-то из демонов держит удаленные файлы.

Давайте поподробнее. Про нулевой случай всё понятно — приложение пытается записать в /var, он у вас смонтирован отдельным разделом, а вы смотрите на место в корне. Или такая же фигня с каким-нибудь /dev/shm, /run или любым другим tmpfs. В том числе и с самим /tmp — он из-за разных глюков может смонтироваться с размером в несколько килобайт.
Also, «не туда» может возникнуть по причине того, что вы смонтировали новый раздел в не пустой каталог. Например, у вас стало заканчиваться место в /var, вы подключили новый hdd, скопировали всё, смонтировали новый hdd в /var. Логично, что место в «старом» /var (который был частью корневого раздела и ею остаётся на физическом уровне) не освободится и вы никак не узнаете, что у вас там лежит ещё 50 гб хлама, который вы не сможете увидеть, пока не отмонтируете новый /var и не удалите файлы явно.

Про inodes тоже понятно. Если у вас много-много мелких файлов, то inodes будут кончаться сильно быстрее, чем место на диске. Каждый файл будет кушать хотя бы одну inode. Если количество inodes меньше, чем блоков на диске — то они закончатся быстрее, чем свободное место (т.е. блоки).
Починить на лету это сложно (ну кроме как удалением той самой кучи мелких файлов). На типовом стеке LAMP-ы это случается чаще всего из-за файлов сессий (если вы их вынесли куда то из /var/lib/php5 и не настроили чистку нового каталога по крону) или из-за битриксов — небольшой сайт на битриксе с включенным кешированием скушает вам 300-400k inodes (а на digitalocean вам на виртуалке за 5 баксов дают 2kk inodes). Большой сайт на битриксе влегкую кушает 2-3kk inodes и не давится.

Проверить, сколько у вас inodes свободно можно командой df -i:
Код:
root@server:~# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
rootfs 1966080 1966079 1 100% /
...
IFree — целая одна. Нужно чистить (удалять мелкие файлы). Ну или просто большие файлы, но это будет куда менее эффективно.

Ну и второй вариант — самый непонятный. df говорит, что места нет, df -i говорит, что inodes есть, du -h / говорит, что файлы занимают меньше половины всего места, блаблабла, куда делось место — непонятно. Возможная причина — ниже.

Когда вы удаляете файлы, используемый в данный момент запущенным приложением, файл не удаляется вообще — только стирается его inode и файл больше не видно в ls. То есть, если вы удалите 100G-овый /var/log/syslog не останавливая syslog — то место не освободится, а syslog продолжит писать в файл по старому адресу (при этом посмотреть этот файл штатными средствами системы вы уже не сможете, так как ни один новый процесс уже не сможет обратиться к этому файлу).
Проверяется такое очень легко — командой lsof | grep deleted:
Код:
root@server:~# lsof | grep deleted
syslog-ng 196 root 14w REG 252,2 8082186240 1704154 /var/log/syslog (deleted)
syslog-ng 196 root 20w REG 252,2 14302392320 1708519 /var/log/mail.log (deleted)
syslog-ng 196 root 25w REG 252,2 14302023680 1708509 /var/log/mail.info (deleted)
syslog-ng 196 root 26w REG 252,2 14301499392 1709839 /var/log/mail.warn (deleted)
mysqld 582 mysql 4u REG 252,2 0 1707925 /tmp/ib9mkQir (deleted)
mysqld 582 mysql 5u REG 252,2 215 1708488 /tmp/ib5CiO9t (deleted)
mysqld 582 mysql 6u REG 252,2 0 1709769 /tmp/ibLxoM0w (deleted)
mysqld 582 mysql 7u REG 252,2 0 1709868 /tmp/ibRdFsTz (deleted)
mysqld 582 mysql 11u REG 252,2 0 1709877 /tmp/ibJklN0D (deleted)
Здесь мы хорошо видим, что файлы, которые используют syslog-ng и mysqld, удалили, но демоны всё ещё висят над этими файлами и пишут в них.
«Починить место» в данном случае можно так:
Код:
root@server:~# /etc/init.d/mysql stop; /etc/init.d/mysql start
Код:
root@server:~# /etc/init.d/syslog-ng stop; /etc/init.d/syslog-ng start
Само собой, если у вас там другие процессы в первом столбце — то перезапускать нужно их.
 
Сверху Снизу