Debian.pro

Блог для пользователей и администраторов Debian


Кончилось место на сервере? А файлов меньше чем занятого места?

Так и не смог придумать нормальный заголовок, так что суть — в следующем абзаце.
Нередко случается такое, что приложение говорит «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

Само собой, если у вас там другие процессы в первом столбце — то перезапускать нужно их.


Комментарии (15):

  1. Borz :

    Лучше не «restart», а явно «stop» и «start» выполнять — не всегда при перезапуске демон полностью завершается…

  2. Да, для апстарта так разумнее делать. Чего то я забыл про него.

  3. yukra :

    Еще можно:
    1) В выводе lsof посмотреть pid процесса и имя файла
    2) Пойди в /proc/PID/fd, сказать «ls -la», увидеть что-то, типа «l-wx—— 1 yukra yukra 64 апр. 1 03:43 1 -> /run/shm/test (deleted)»
    3) Сказать «gdb -p PID» и потом «p close (1)» где «1″ это имя ссылки из п. 2

    Важно: Пока не наберёте detach, либо не выполните continue (c), процесс будет находиться в остановленном состоянии.
    Важно2: отобрать файл, который например отдает апач — достаточно безболезненно (ну не считая того что клиент, качающий этот файл, обламается), а отобрать у мускуля файл, в который мускуль пишет — может закончиться печалькой.

  4. cru5ade :

    lsof | grep deleted Гениально!! вчера два часа убил поиском кто съел свободное место, и только потом вспомнил про эту команду. Спасибо!

  5. Влад :

    Да не за чт

  6. А вы команды разделяете точкой с запятой?
    Вот
    /etc/init.d/mysql stop; /etc/init.d/mysql start

    Это какой эффект даёт?

  7. Кстати да, на VPS от DO столкнулся с тем, что битрих занял вообще все inode, умаялся убивать эти сотни тысяч файлов.
    Ни одна команда с гугла и хабра не помогала, в итоге, после пары часов помогло:
    find . -name ‘*’ -print0 | xargs -0 rm

  8. Влад :

    Ну это известный способ. Xargs, кстати, будет работать очень медленно — лучше find с опциями -delete -print запускать.

  9. Влад :

    > Это какой эффект даёт?
    Чтобы команды выполнялись по очереди, независимо от результата выполнения предыдущей.
    && — выполнять следующую только при успешном выполнении предыдущей.

  10. Просто все рецепты из интернета вываливались с ошибкой, а именно xargs сработал.
    Про && знал, а про ; не в курсе. Похоже linux можно всю жизнь изучать )))

  11. Влад :

    Есть ещё || — выполнять следующую команду, только если предыдущая вывались с ненулевым exit code

    find . -name «*_sess» -print -delete будет нормально работать (и быстро на большом кол-ве файлов, быстрее только перлом, но там запомнить нереально).

  12. Andrey :

    После остановки/запуска апача и mysql сервер заработал, сайты стали доступны. Но что дальше? Команда lsof | grep deleted выводит то же самое. Где искать эти файлы? в /tmp/ их нет. И как предотвратить проблему? Из-за этого посыпалось несколько таблиц в базе, хотелось бы по-умному сделать. Все еще непонятно чем забит диск.

  13. > 12
    Сумбурненько.

    Естественно, deleted-файлов в /tmp не будет — на то они и deleted.

    Останови все демоны и смотри, что deleted-файлов после них не осталось. Если остались — смотри по пиду процесса, кто держит и разбирайся с тем, почему процесс не умер.

  14. Andrey :

    нашел причину, один из сайтов клиента писал в лог-файл. файл стал весить 41Гб, удалил, таблицы базы восстановил, хорошо что не критические данные хранились. а с deleted-файлами и процессами еще повожусь, спасибо за совет)

  15. Не за что

Написать комментарий