Файловые системы: df, du, иноды и куда делось место

Рейтинг: 67.6% · 8 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Файловые системы: df, du, иноды и куда делось место

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам
  25. Файловые системы: df, du, иноды и куда делось место (вы здесь)
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Звонок в три часа ночи: сервис лёг, в логах "No space left on device", база не пишет, nginx отдаёт 500. Классика. Ты заходишь по ssh, набираешь df, и дальше начинается самое интересное - потому что иногда место есть, а файлы всё равно не создаются. Или ты удалил гигабайтный лог, а место не вернулось. Этот урок про то, как пошагово найти, куда делось место на диске в Linux, и не гадать, а точно знать. Связка df du - твои первые две команды в любом таком разборе, и сегодня мы разберём их до колонок вывода, а заодно посмотрим, как это делают в 2026 году более быстрыми инструментами.

Механика: почему "место на диске" - это две разные вещи

Файловая система хранит две вещи отдельно: сами данные (блоки на диске) и метаданные о файлах (иноды). Инод (inode) - это карточка файла: кому принадлежит, права, временные метки, размер и где лежат блоки с данными. Имя файла в иноде НЕ хранится - имя живёт в каталоге и просто ссылается на номер инода. Поэтому у одного инода может быть несколько имён (жёсткие ссылки), и это пригодится дальше.

Ключевой вывод для новичка: иноды кончаются отдельно от места. В ext4 число инодов фиксируется на этапе создания ФС (mkfs, параметр bytes-per-inode) и онлайн не меняется. Если у тебя миллионы крошечных файлов - сессии PHP, мелкие кэши, очереди писем - ты упрёшься в лимит инодов раньше, чем кончатся гигабайты. Тогда df -h покажет "свободно 40G", а система честно ответит "No space left on device". Это первая ловушка.

Важная актуализация на 2026: на новых серверах под Astra Linux, RED OS, RHEL-семейством и многих образах в облаках по умолчанию всё чаще XFS, а не ext4. У XFS иноды выделяются динамически, поэтому колонка "всего инодов" в df -i не фиксирована и плавает от запуска к запуску - пугаться этого не надо, у XFS нет того жёсткого потолка инодов, что у ext4 (потолок есть, но он процент от размера ФС и очень большой). На Btrfs картина ещё интереснее: там df вообще условен из-за сжатия и снапшотов, отдельно про это ниже. Понимать, какая под тобой ФС, важно: команда mount или findmnt покажет тип.

Код: Выделить всё

findmnt -t ext4,xfs,btrfs    # какие ФС и где смонтированы
df -h     # сколько занято места (блоков данных)
df -i     # сколько занято инодов (карточек файлов)
Вторая базовая идея: место освобождается только когда у файла нет ни одного имени в каталоге И нет ни одного открытого дескриптора. Удалил файл (rm) - убрал имя. Но если процесс держит файл открытым, инод и его блоки живут дальше, пока процесс не закроет дескриптор или не умрёт. Отсюда вечная загадка "удалил, а место не вернулось".

Изображение

df -h и df -i: читаем по колонкам

Начинаем всегда с df. Связка df du работает так: df говорит ГДЕ проблема (на какой точке монтирования), du говорит В ЧЁМ она (какой каталог раздулся).

Код: Выделить всё

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        49G   47G  1.8G  97% /
/dev/sda2       197G   45G  143G  24% /var
tmpfs           3.9G  1.2M  3.9G   1% /run
overlay          49G   47G  1.8G  97% /var/lib/docker/overlay2/...
Разбор по колонкам:
  • Filesystem - устройство или раздел. tmpfs и overlay - это не диск: tmpfs живёт в RAM, overlay - слои контейнеров Docker, которые на самом деле лежат на /. Их отдельные строки часто путают новичков.
  • Size / Used / Avail - всего / занято / доступно.
  • Use% - процент занятого. Сюда смотри в первую очередь. 97% на / (корне) - это тревога. Заметь: Used + Avail обычно МЕНЬШЕ, чем Size. Для ext4 причина - резерв около 5% места под root (чтобы система не встала колом и демоны root могли дописать при переполнении). df честно вычитает этот резерв из Avail, поэтому "0 доступно" по df ещё не значит, что физически 0 байт - root туда впишется. Резерв на больших дисках под данные часто снижают через tune2fs -m 1.
  • Mounted on - точка монтирования. Запомни её: дальше копать du будешь именно там, где Use% высокий.
Если df -h показал, что место вроде есть, а файлы не пишутся - проверяй df -i:

Код: Выделить всё

$ df -i
Filesystem      Inodes  IUsed IFree IUse% Mounted on
/dev/sda1      3276800 3276792     8  100% /
/dev/sda2     13107200  41210 13065990  1% /var
Колонки те же по смыслу, но про иноды: Inodes (всего), IUsed (занято), IFree (свободно), IUse% (процент). Видишь IUse% 100% на / при том, что по месту было, скажем, 60%? Поздравляю, ты нашёл классику: кончились inodes в Linux. Где-то лежит каталог с сотнями тысяч мелких файлов. Лечится не "почисткой больших файлов", а поиском каталога-рассадника. На XFS, кстати, IUse% почти никогда не упрётся в 100% сам по себе - там иноды растут динамически, так что эта беда - в основном про ext4.

Практика: пошаговый поиск, куда делось место на диске

Допустим, df указал на корень / с Use% 97%. Спускаемся по дереву с помощью du. Главная команда du в Linux - с ограничением глубины:

Код: Выделить всё

$ sudo du -h --max-depth=1 -x / 2>/dev/null | sort -rh | head -15
27G   /var
12G   /usr
4.1G  /home
2.3G  /opt
49G   /
Что тут происходит: du -h считает размеры в человекочитаемом виде, --max-depth=1 показывает только верхний уровень, -x (важно!) не даёт du уходить на другие смонтированные ФС - иначе он посчитает примонтированный /var как часть / и собьёт тебя с толку. sort -rh сортирует по размеру в обратном порядке (-h понимает K/M/G), head -15 берёт топ. 2>/dev/null глушит ошибки "Permission denied" на /proc и подобном. Самый жирный реальный каталог сверху - /var. Ныряем:

Код: Выделить всё

$ sudo du -h --max-depth=1 -x /var | sort -rh | head
24G   /var/log
2.1G  /var/lib
$ sudo du -h --max-depth=1 -x /var/log | sort -rh | head
22G   /var/log/journal
Два-три шага - и виновник найден: разбух системный журнал systemd. Тут есть прямой инструмент вместо du: journalctl --disk-usage покажет, сколько занимает журнал, а почистить аккуратно (не rm!) - journalctl --vacuum-size=500M или --vacuum-time=7d. Чтобы не пухло впредь - SystemMaxUse в /etc/systemd/journald.conf. Это актуальный на 2026 способ, на systemd-системах он надёжнее ручного удаления файлов журнала.

Для интерактивного режима классика - ncdu: он один раз сканирует каталог и даёт ходить по дереву стрелками, Enter заходит внутрь, d удаляет выделенное:

Код: Выделить всё

sudo ncdu -x /
Актуализация на 2026: если каталог огромный (миллионы файлов) и на SSD/NVMe, ncdu сканирует медленно, потому что однопоточный. Современная замена - gdu (на Go, многопоточный, заточен под SSD, тот же TUI, но в разы быстрее) и dua (dua i для интерактива). Для быстрой сводки по разделам вместо df многие в 2026 ставят duf - это красивый клон df с группировкой по типам ФС и выводом в JSON (duf --json) для скриптов. Все они есть в репозиториях Debian/Ubuntu (apt install ncdu gdu duf), RHEL/Fedora (dnf install ncdu), в Astra Linux и RED OS ncdu штатный, gdu/duf иногда ставят из бинарника с GitHub. Для новичка ncdu остаётся самым дружелюбным: не надо помнить флаги, просто ходишь и смотришь.

Отдельно про большие файлы - иногда диск съел не каталог, а один монстр (дамп базы, незаротированный лог, core dump):

Код: Выделить всё

$ sudo find / -xdev -type f -size +1G -printf '%s %p\n' 2>/dev/null | sort -nr | head
6442450944 /var/lib/mysql/ib_logfile_old
3221225472 /home/deploy/dump.sql
Флаг -xdev не даёт find уходить на другие смонтированные ФС - ищем именно на проблемном разделе. %s - размер в байтах, %p - путь.

Грабли: df и du расходятся, а место "не вернулось"

Грабля 1. du и df показывают разные числа. Это нормально, и у этого несколько частых причин.

Первая и самая частая - удалённый, но открытый файл. du ходит по каталогам и видит имена. Если файл удалён (имени нет), но процесс держит его открытым, du его НЕ посчитает, а df посчитает занятое место честно. Отсюда "df говорит 90%, а du насчитал 40%". Ищем держателей так:

Код: Выделить всё

$ sudo lsof +L1
COMMAND  PID USER  FD   TYPE DEVICE   SIZE/OFF NLINK NODE NAME
nginx    812 root  3w   REG  8,1    21474836480   0  131 /var/log/nginx/access.log (deleted)
+L1 отбирает файлы, у которых число жёстких ссылок (NLINK) меньше 1, то есть 0 - имени в каталоге уже нет. Колонка NLINK = 0 и пометка (deleted) в конце - вот он. SIZE/OFF тут ~20 ГБ, висящих мёртвым грузом. Чтобы сразу найти самого жирного, отсортируй по 7-й колонке: lsof +L1 | sort -k7 -rn. PID 812 - процесс-держатель. Лечение: либо аккуратно перечитать сервис (для nginx - systemctl reload nginx, демон переоткроет лог-файл), либо, если файл больше не нужен, обнулить его на месте через дескриптор, не убивая процесс:

Код: Выделить всё

sudo truncate -s 0 /proc/812/fd/3
Здесь 812 - PID, 3 - номер дескриптора из колонки FD (3w означает дескриптор 3, открыт на запись). Мораль: не удаляй активные логи через rm - используй truncate -s 0 или настрой logrotate с директивой copytruncate либо postrotate-сигналом сервису.

Вторая причина расхождения - скрытое потребление под точкой монтирования. Если в каталог, скажем /mnt/data, что-то писали ДО того, как туда смонтировали диск, эти файлы никуда не делись - они лежат на родительской ФС, спрятанные под точкой монтирования. df их не видит (для него под /mnt/data уже другая ФС), а место на корне тает. Проверка: временно сделать umount и посмотреть, что под точкой, либо сравнить du -x по корню (без пересечения границ ФС) с тем, что показывает df по /.

Третья причина характерна для XFS и ext4: файлы с дырами (sparse) и спекулятивная преаллокация. XFS заранее резервирует место под растущий файл, поэтому df может на время показать больше занятого, чем du. Обычно это саморассасывается, специально лечить не нужно.

Грабля 2. Чистишь большие файлы, а IUse% всё равно 100%. Ты борешься не с тем. При нехватке инодов нужен не объём, а количество. Ищем каталог с диким числом мелких файлов. Надёжный однострочник:

Код: Выделить всё

$ sudo find / -xdev -type d 2>/dev/null -exec sh -c 'echo "$(ls -A "$1" 2>/dev/null | wc -l) $1"' _ {} \; | sort -rn | head
482310 /var/lib/php/sessions
98214 /home/app/cache/twig
Первая колонка - число элементов прямо в каталоге. 482 тысячи сессий PHP - вот они и съели иноды. Чистим протухшее, настраиваем сборку мусора (для PHP - session.gc_maxlifetime + cron или systemd-таймер), и IFree оживает. Помни: на ext4 расширить число инодов на лету нельзя - только пересоздать ФС; на XFS этой проблемы по сути нет.

Грабля 3. Забывают про квоты. Если место по df есть, инодов хватает, а пользователь жалуется "не могу записать" - может быть включена дисковая квота. Смотри quota -u имя_пользователя или repquota -a (нужен пакет quota и опция usrquota/grpquota в /etc/fstab, на XFS квоты включаются опциями монтирования и смотрятся через xfs_quota). Квота - не баг, а настроенный лимит, но в диагностике про неё забывают.

Грабля 4. Контейнеры и Btrfs. На хосте с Docker место часто съедает /var/lib/docker (старые образы, тома, логи контейнеров). df по / растёт, du по нему долгий - быстрее спросить docker system df. На Btrfs обычный df врёт из-за сжатия и метаданных - там правильнее btrfs filesystem usage /.

Мини-лаба: повтори руками прямо сейчас

Безопасно на любой тестовой машине или в контейнере:
  • Выполни findmnt -t ext4,xfs - узнай тип своей ФS. Затем df -h и df -i, найди раздел с самым высоким Use% и IUse%. Сравни запас места и инодов - где меньше.
  • Прогони sudo du -h --max-depth=1 -x / 2>/dev/null | sort -rh | head и за 2-3 спуска дойди до самого тяжёлого каталога. Запиши путь.
  • Поставь ncdu (и, если есть, gdu) и пройди тот же путь интерактивно - почувствуй разницу в удобстве и скорости.
  • Смоделируй удалённый открытый файл: в первом терминале head -c 200M /dev/zero > /tmp/test.bin, потом tail -f /tmp/test.bin. Во втором: rm /tmp/test.bin, затем sudo lsof +L1 | grep test.bin - увидишь NLINK 0 и (deleted). Сравни df до и после rm: место не вернулось. Закрой tail (Ctrl+C) - вернётся.
Контрольные вопросы
  • df -h показывает 30% занятого, но система пишет "No space left on device". Какую команду запустишь следующей и что будешь искать в её выводе? Почему на XFS этот сценарий маловероятен?
  • du насчитал 40 ГБ, а df говорит, что занято 90 ГБ. Назови две причины расхождения и команду для проверки самой частой из них.
  • Что означает NLINK = 0 и пометка (deleted) в выводе lsof +L1, и как освободить место, не теряя работающий процесс?
  • Почему при нехватке инодов на ext4 бесполезно удалять большие файлы, что искать вместо этого и почему на XFS этой проблемы почти нет?
Что запомнить
Место на диске - это блоки и иноды, они кончаются независимо. Сначала df -h (где проблема) и df -i (не в инодах ли дело), потом du -h --max-depth=1 -x со спуском вниз, либо ncdu/gdu для интерактива, либо duf для красивой сводки. Если du и df расходятся - первым делом lsof +L1 (удалённый, но открытый файл) и проверка скрытого потребления под точкой монтирования. Активные логи не удаляй через rm, обнуляй через truncate -s 0; раздутый журнал systemd чисти journalctl --vacuum-size/--vacuum-time. Знай тип своей ФС: на XFS иноды динамические, на Btrfs и в Docker у места своя бухгалтерия. Эта связка закрывает 95% случаев "закончилось место в Linux".
👍2 ❤️3 🔥 😄 🤔
Аватара пользователя
jstevens
Сообщения: 1
Зарегистрирован: 13 май 2026, 16:48

Re: Файловые системы: df, du, иноды и куда делось место

Сообщение jstevens »

Вот это про lsof +L1 - прям откровение. Месяц назад на проде удалил жирный лог nginx через rm, место не вернулось, ребутнул сервак как дурак. Теперь понятно что надо было truncate или systemctl reload. Спасибо!
👍 ❤️ 🔥 😄 🤔1
Аватара пользователя
RaspberryAdmin
Сообщения: 1
Зарегистрирован: 14 май 2026, 05:29

Re: Файловые системы: df, du, иноды и куда делось место

Сообщение RaspberryAdmin »

Поставил gdu вместо ncdu по совету из урока - на NVMe с кучей мелочи реально летает, ncdu там минуту думал. Но для удалёнки по ssh ncdu всё равно держу, он точно везде есть. И findmnt чтобы тип ФС глянуть - не знал, всегда mount грепал.
👍1 ❤️ 🔥 😄 🤔1
Ответить
← Предыдущая глава
Кто грузит диск: iotop и атрибуция io процессам
Следующая глава →
Глубокая диагностика блочного слоя: blktrace и biolatency

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
Похожие запросы: lsof кто держит файл и порт в linux.gitignore: как игнорировать файлыGit LFS: большие файлы в репозитории

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость