Вопрос или проблема
У меня есть диск btrfs (без рейда), который показывает очень большую разницу между du и df:
$ df -h /pgdata
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-pgdata 85G 77G 7.1G 92% /pgdata
$ du -sh /pgdata
56G /pgdata
И команды btrfs дают мне тот же результат:
$ btrfs fi df -h /pgdata/
Data, single: total=82.94GiB, used=75.63GiB
System, DUP: total=32.00MiB, used=16.00KiB
Metadata, DUP: total=1.00GiB, used=365.73MiB
GlobalReserve, single: total=228.33MiB, used=0.00B
$ btrfs fi du -s /pgdata/
Total Exclusive Set shared Filename
55.84GiB 55.36GiB 491.34MiB /pgdata/
Нет подтомов (как я думаю), btrfs subvolume list /pgdata
пуст.
Я запустил btrfs balance start /pgdata/ -dusage=66
, но это особо не изменило ситуацию.
$ btrfs fi usage /pgdata/
Overall:
Device size: 85.00GiB
Device allocated: 85.00GiB
Device unallocated: 1.00MiB
Device missing: 0.00B
Used: 76.50GiB
Free (estimated): 7.15GiB (min: 7.15GiB)
Data ratio: 1.00
Metadata ratio: 2.00
Global reserve: 228.52MiB (used: 0.00B)
Data,single: Size:82.94GiB, Used:75.79GiB (91.38%)
/dev/mapper/ubuntu--vg-pgdata 82.94GiB
Metadata,DUP: Size:1.00GiB, Used:365.78MiB (35.72%)
/dev/mapper/ubuntu--vg-pgdata 2.00GiB
System,DUP: Size:32.00MiB, Used:16.00KiB (0.05%)
/dev/mapper/ubuntu--vg-pgdata 64.00MiB
Unallocated:
/dev/mapper/ubuntu--vg-pgdata 1.00MiB
Это не удалённые иноды являются проблемой (машина была перезагружена 3 часа назад) и:
$ lsof /pgdata |grep deleted
postgres 4107 postgres 4u REG 0,58 16777216 238658 /pgdata/postgresql/13/main/pg_wal/00000001000001E40000008A (deleted)
postgres 5589 postgres 45u REG 0,58 16777216 238753 /pgdata/postgresql/13/main/pg_wal/00000001000001E50000000E (deleted)
postgres 5590 postgres 45u REG 0,58 16777216 222523 /pgdata/postgresql/13/main/pg_wal/00000001000001E40000006A (deleted)
postgres 5591 postgres 26u REG 0,58 16777216 238992 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000F3 (deleted)
postgres 5592 postgres 52u REG 0,58 16777216 238986 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000ED (deleted)
postgres 5595 postgres 28u REG 0,58 16777216 238995 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000F6 (deleted)
postgres 5596 postgres 19u REG 0,58 16777216 222523 /pgdata/postgresql/13/main/pg_wal/00000001000001E40000006A (deleted)
postgres 5597 postgres 44u REG 0,58 16777216 222523 /pgdata/postgresql/13/main/pg_wal/00000001000001E40000006A (deleted)
postgres 5598 postgres 12u REG 0,58 16777216 238986 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000ED (deleted)
postgres 5604 postgres 85u REG 0,58 16777216 238988 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000EF (deleted)
postgres 5605 postgres 61u REG 0,58 16777216 238986 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000ED (deleted)
postgres 12936 postgres 58u REG 0,58 16777216 238995 /pgdata/postgresql/13/main/pg_wal/00000001000001E4000000F6 (deleted)
Я нашёл другие сообщения об этой проблеме, но ни в одном не было такой большой разницы (примерно на 40% больше, чем должно быть) и это всегда были метаданные или снимок. Здесь, похоже, это не так.
У кого-нибудь есть идея, почему не хватает 20GiB свободного места?
Одна из возможных причин большего распределения пространства btrfs для данных, чем видимых данных, это недоступные части экстентов (данные в экстентах, содержащие более старые версии содержимого файла, которые были перезаписаны).
Чтобы анализировать такие проблемы, я создал btdu, профилировщик использования диска для btrfs:
https://github.com/CyberShadow/btdu
Инструмент определит истинную причину расхождения.
Если ваш сервер хорошо настроен, большая часть операций ввода-вывода на хранение должна быть на запись, и всё чтение, кроме (большого) первого, должно выполняться из оперативной памяти: ваш сервер должен практически только записывать изменённые в оперативной памяти блоки на диск.
Так как postgreSQL постоянно выполняет небольшие операции записи (в зависимости от размера его страницы), не будет удивительно, что все файлы данных postgreSQL будут иметь высокий уровень фрагментации
Я заметил ту же “проблему” (потеря более 28% на терабайтной файловой системе BTRFS) в настройке, где у меня есть виртуальные машины, хранящиеся на большой файловой системе BTRFS, и каждая VM использует COW VMDK файлы в качестве дисков, а некоторые VM работают с базами данных (особенно MariaDB / postgreSQL)
Способ вернуть большую часть этого пространства был следующим:
$ sudo btrfs balance start -musage=100 -dusage=100 /mnt/vm
$ sudo btrfs filesystem defrag -r -f -v /mnt/vm
и снова выполнить балансировку:
$ sudo btrfs balance start -musage=100 -dusage=100 /mnt/vm
Таким образом мне удалось вернуть большую часть “потерянного” пространства
Пожалуйста, также обратите внимание, что прежде всего вы должны прочитать:
Вот результаты в моём случае:
Реальные данные (оригинальное и последнее состояние):
$ sudo btrfs fi du -s /mnt/vm
Total Exclusive Set shared Filename
669.62GiB 669.22GiB 401.46MiB /mnt/vm
Использование файловой системы BTRFS (оригинальное состояние)
$ sudo btrfs fi usage /mnt/vm
Overall:
Device size: 1000.00GiB
Device allocated: 955.07GiB
Device unallocated: 44.93GiB
Device missing: 0.00B
Device slack: 0.00B
Used: 950.71GiB
Free (estimated): 46.74GiB (min: 24.28GiB)
Free (statfs, df): 46.74GiB
Data ratio: 1.00
Metadata ratio: 2.00
Global reserve: 512.00MiB (used: 0.00B)
Multiple profiles: no
Data,single: Size:949.01GiB, Used:947.19GiB (99.81%)
/dev/mapper/vgu2nvme-lvvm 949.01GiB
Metadata,DUP: Size:3.00GiB, Used:1.76GiB (58.56%)
/dev/mapper/vgu2nvme-lvvm 6.00GiB
System,DUP: Size:32.00MiB, Used:144.00KiB (0.44%)
/dev/mapper/vgu2nvme-lvvm 64.00MiB
Unallocated:
/dev/mapper/vgu2nvme-lvvm 44.93GiB
Последнее состояние после всех операций (первая балансировка восстановила только 10 GiB):
$ sudo btrfs fi usage /mnt/vm
Overall:
Device size: 1000.00GiB
Device allocated: 711.07GiB
Device unallocated: 288.93GiB
Device missing: 0.00B
Device slack: 0.00B
Used: 708.02GiB
Free (estimated): 291.72GiB (min: 147.26GiB)
Free (statfs, df): 291.72GiB
Data ratio: 1.00
Metadata ratio: 2.00
Global reserve: 512.00MiB (used: 0.00B)
Multiple profiles: no
Data,single: Size:709.01GiB, Used:706.21GiB (99.61%)
/dev/mapper/vgu2nvme-lvvm 709.01GiB
Metadata,DUP: Size:1.00GiB, Used:926.33MiB (90.46%)
/dev/mapper/vgu2nvme-lvvm 2.00GiB
System,DUP: Size:32.00MiB, Used:144.00KiB (0.44%)
/dev/mapper/vgu2nvme-lvvm 64.00MiB
Unallocated:
/dev/mapper/vgu2nvme-lvvm 288.93GiB
Итак, не идеально (примерно 4% потерянного пространства не удалось восстановить), но это лучший результат, который я смог достичь!
Примечание: все эти операции были выполнены онлайн с файловой системой, смонтированной и с запущенными около ~ 20 VM на ней.
Возможно, единственный способ восстановить последние 4% будет в холодной копии данных на другую недавно отформатированную файловую систему BTRFS (= остановка ~20 рабочих VM и выполнение cp -a
)…
Так что если кто-то знает, как восстановить последние 4% потерянного пространства без копирования данных на другую файловую систему, это было бы очень полезно.
Ответ или решение
На Btrfs-файловой системе часто наблюдаются несовпадения между командами du
и df
. В данном случае описывается ситуация, когда команда df
показывает, что почти 77GB из 85GB заняты, в то время как du
отображает лишь 56GB. Эта значительная разница может быть вызвана несколькими факторами, которые мы рассмотрим подробнее.
Возможные причины расхождения между du и df
-
Удаленные, но еще открытые файлы: Это наиболее распространенная причина рассогласования. В вашем случае несколько файлов PostgreSQL указаны как удаленные, но продолжают оставаться в памяти, пока процесс не завершится или система не будет перезагружена.
-
Фрагментация: Сильно фрагментированные файлы, особенно при интенсивных операциях записи, могут занимать больше места на диске, чем отображается в
du
. Это часто бывает с базами данных, подобными PostgreSQL. -
Резервное пространство Btrfs: Btrfs резервирует пространство для метаданных, глобальных резервов и других системных данных, что может не быть видимым в
du
. -
Дупликация данных: Например, использование CoW (Copy-on-Write) может привести к тому, что Btrfs фактически выделяет больше места для данных, чем кажется необходимо.
Рекомендации по решению проблемы
Оптимизация с помощью балансировки: Проведение операций балансировки с использованием параметров -musage=100 -dusage=100
может помочь перераспределить данные более эффективно, уменьшая фрагментацию и освобождая некоторое пространство. Тем не менее, вы уже попробовали btrfs balance
, и возможно, его недостаточно.
Дефрагментация файловой системы: Запуск команды btrfs filesystem defrag
может значительно снизить уровень фрагментации, особенно для файлов баз данных, которые часто записываются на диск небольшими блоками.
Инструменты для анализа Btrfs: Использование специализированных инструментов, таких как btdu
, может дать более детальное представление о распределении пространства в Btrfs, позволяя выявить истинные причины расхождения.
Заключение
В случае Btrfs, особенно при работе с интенсивными базами данных, распределение дискового пространства может быть довольно сложным. Явное расхождение между командами du
и df
в вашем случае может быть связано с множеством факторов, включая фрагментацию, удаленные файлы и системные резервы. Использование балансировки и дефрагментации, а также специализированных инструментов для анализа Btrfs, сможет помочь вам оптимизировать использование пространства на файлосистеме.
Если у вас остались дополнительные вопросы или возникли трудности при выполнении рекомендованных действий, пожалуйста, не стесняйтесь обращаться за дополнительной консультацией.