LVM thin provisioning выделяет томам виртуальный размер и тратит физическое место только под записанные блоки. Все тонкие тома берут чанки из одного thin pool, поэтому том на 1 ТиБ может занимать 20 ГиБ, пока в него не начали писать. Обратная сторона: пул заканчивается, новые записи падают с ошибкой, а при исчерпании metadata пул уходит в режим только для чтения.
Дальше весь цикл работы: создание пула и тонких томов, контроль data_percent и metadata_percent, авторасширение через dmeventd, порядок действий при переполнении данных и метаданных, проверка целостности через thin_check и fsck. Команды рассчитаны на LVM 2.03 (RHEL 9/10, Ubuntu 22.04/24.04) и ядро 5.10 и новее.
Что такое LVM thin provisioning и зачем он нужен
Thin provisioning - режим LVM, в котором том получает виртуальный размер, а физические чанки выделяются в момент записи из общего пула. Пул (thin pool) состоит из двух внутренних томов: данных и метаданных. Пустой тонкий том места почти не занимает, расход появляется только при форматировании и первой записи.
Чем thin provisioning отличается от обычных LVM-томов
Обычный логический том (thick, он же linear) резервирует место сразу: команда lvcreate -L 100G -n data vg забирает 100 ГиБ из группы томов, и эти 100 ГиБ недоступны другим томам, даже если файлов внутри на 3 ГиБ. Тонкий том создаётся с флагом --virtualsize и физически занимает столько, сколько записано.
| Параметр | Обычный (thick) том | Тонкий (thin) том |
|---|---|---|
| Выделение места | Весь размер сразу, при создании | По мере записи, чанками из пула |
| Переподписка | Невозможна: сумма размеров упирается в объём VG | Возможна: сумма виртуальных размеров превышает пул в разы |
| Снапшот | Копия изменённых блоков, требует своего места | COW-снапшот на уровне чанков, создаётся за секунды |
| Расход места | Неэффективен для неполных томов | Экономичен, место уходит под реальные данные |
| Риск | Предсказуемое поведение, том не вырастет неожиданно | При исчерпании пула записи падают с ошибкой |
Переподписка (overprovisioning) даёт главный практический эффект. В группе томов на 1 ТиБ можно создать десять тонких томов по 200 ГиБ и держать в них 300 ГиБ реальных данных. Обычные тома такого не позволяют.
Сценарии, где тонкие тома выигрывают: диски виртуальных машин в Proxmox и KVM (тип LVM-thin), тома для контейнеров, песочницы и CI-раннеры, которые живут несколько часов, снапшоты перед обновлением или миграцией. Обратные случаи: база данных с постоянным ростом записи и без мониторинга, стенды без свободных экстентов в VG, системы, где нужна гарантия записи в любой момент.
Если выбираете между технологиями, полезны материалы по программным RAID-массивам на Linux (mdadm, ZFS, LVM) и по настройке ZFS: в ZFS тонкое выделение встроено в zvol и dataset, в LVM его включают явно и контролируют отдельно.
Данные и metadata: что это и почему важно
Пул состоит из двух subvolume: [pool_tdata] под данные и [pool_tmeta] под метаданные. Метаданные - это btree: соответствие виртуальных блоков чанкам, деревья снапшотов, счётчики транзакций. Каждый выделенный чанк требует записи в это дерево.
Расход metadata считается просто. Chunk size по умолчанию 64 КиБ, на каждую запись в дерево уходит около 64 байт. Для 1 ТиБ данных это 16 777 216 чанков и примерно 1 ГиБ метаданных. Практическое правило: закладывайте не меньше 0,1% от объёма данных, а при большой ферме снапшотов больше. Снапшоты расходуют metadata даже без изменений в данных, потому что каждому нужен собственный набор деревьев.
Последствия переполнения различаются:
- Закончились данные: новые чанки не выделяются, приложения получают ошибки ввода-вывода с кодом ENOSPC. Уже записанное читается, запись в новые блоки невозможна.
- Закончились metadata: пул не может отслеживать размещение блоков, ядро переводит его в режим только для чтения. Восстановление требует свободного места, а испорченное дерево способно унести с собой часть данных.
При создании пула LVM по умолчанию делает запасной metadata-том (pool metadata spare), обычно с именем lvol0. Он занимает немного места в VG, зато нужен для автоматического ремонта через lvconvert --repair. Отключать его не стоит.
Создание thin pool и тонких томов: пошаговая инструкция
Перед первой командой сделайте резервную копию данных с дисков, которые отдаёте под LVM. Ошибка в имени устройства при pvcreate или lvcreate стирает подписи и таблицы разделов, а переполнение metadata способно сделать тома нечитаемыми. Отдельный стенд или виртуальная машина с блочными дисками снимают большую часть этого риска.
Для тестового прогона подойдёт облачный сервер с дополнительными томами, например в Timeweb Cloud: диски добавляются в панели, а удаление стенда не затрагивает рабочие данные.
Подготовка физических томов и группы томов
pvcreate /dev/nvme0n1p1 /dev/nvme1n1p1 pvs vgcreate vg_data /dev/nvme0n1p1 /dev/nvme1n1p1 vgs
Physical extent по умолчанию равен 4 МиБ, для крупных пулов его можно увеличить флагом -s при vgcreate. Команда pvs показывает, что диски размечены и не заняты чужой файловой системой. Группу томов создавайте с запасом 10-20% свободных экстентов: этот резерв понадобится авторасширению и аварийному lvextend.
Создание thin pool с помощью lvcreate
lvcreate --type thin-pool --name pool --size 500G \
--poolmetadatasize 1G --chunksize 64K vg_data
Разбор параметров:
- --size 500G - физический объём данных пула (tdata).
- --poolmetadatasize 1G - размер tmeta. Для 500 ГиБ данных при chunk 64 КиБ нужно около 512 МиБ, запас вдвое покрывает снапшоты и рост.
- --chunksize 64K - размер чанка, минимальное значение и значение по умолчанию. Меньше чанк: точнее расход места, больше метаданных. Больше чанк (256K, 1M): меньше нагрузка на metadata, но файл на 4 КиБ занимает целый чанк. Для ферм со снапшотами выбирайте 256K и выше.
- --zero для тонких томов смысла не имеет: незанятые чанки читаются как нули, mkfs не увидит старых данных.
- --poolmetadataspare y включён по умолчанию и создаёт резервный metadata-том.
Проверка сразу после создания:
lvs -a vg_data
LV VG Attr LSize Data% Meta% Chunk lvol0 vg_data -wi------- 1.00g pool vg_data twi-aotz-- 500.00g 0.00 0.36 64.00k [pool_tdata] vg_data Twi-ao---- 500.00g [pool_tmeta] vg_data ewi-ao---- 1.00g
Строка pool - сам пул, в квадратных скобках видны внутренние тома, lvol0 - запасной metadata-том. Столбец Attr начинается с t, что означает thin pool.
Создание тонкого тома и файловой системы
lvcreate --virtualsize 1T --thinpool vg_data/pool --name vm100 lsblk mkfs.xfs /dev/vg_data/vm100 mkdir -p /srv/vm100 mount /dev/vg_data/vm100 /srv/vm100 df -h /srv/vm100
Размер тома виртуальный: 1 ТиБ при пуле 500 ГиБ даёт коэффициент переподписки 2. Форматирование добавляет в пул несколько десятков мегабайт, остальное место уйдёт при копировании файлов. Под ext4 команды те же, меняется только mkfs: ext4 умеет уменьшаться, XFS нет, поэтому под растущие данные чаще берут XFS.
Проверить фактический расход: lvs -o lv_name,data_percent,metadata_percent vg_data. Сразу после создания Data% будет около нуля, Meta% уже ненулевой.
Мониторинг заполнения thin pool: данные и metadata
Thin pool без мониторинга превращается в отложенную аварию. Контролировать нужно два процента: data_percent (сколько занято в data) и metadata_percent (сколько занято в btree). Рабочие пороги для алертов: 80% данных и 70% метаданных, критические - 90% и 85%.
Проверка текущего заполнения через lvs
lvs -a -o lv_name,vg_name,lv_size,data_percent,metadata_percent,chunk_size vg_data
LV VG LSize Data% Meta% Chunk pool vg_data 500.00g 42.15 12.30 64.00k [pool_tdata] vg_data 500.00g [pool_tmeta] vg_data 1.00g
Data% 42.15 значит, что под данные занято 42% объёма пула. Meta% 12.30 показывает заполнение btree: этот процент растёт скачками при создании снапшотов и после удаления файлов снижается слабо, потому что освободившиеся блоки дерева остаются зарезервированными под будущие транзакции. Планируйте metadata по пиковому значению, а не по текущему.
Для скриптов удобен машиночитаемый вывод: lvs --reportformat json --nosuffix -o data_percent,metadata_percent vg_data/pool.
Настройка автоматического расширения thin pool
Расширение выполняет демон dmeventd: ядро сообщает ему о пересечении low water mark, а он запускает lvextend. Проверьте, что демон работает:
systemctl status dm-event.socket dm-event.service systemctl enable --now dm-event.socket
Пороги задаются в /etc/lvm/lvm.conf в секции activation:
activation {
thin_pool_autoextend_threshold = 80
thin_pool_autoextend_percent = 20
}
Смысл такой: при заполнении данных выше 80% dmeventd увеличит пул на 20% от текущего размера, для пула 500 ГиБ это плюс 100 ГиБ. Значение threshold = 100 отключает авторасширение. Растёт только data subvolume, metadata демон не трогает, её размер придётся увеличивать вручную. Фактические значения проверяются командой lvmconfig activation/thin_pool_autoextend_threshold, потому что в некоторых сборках параметры заданы иначе, чем в примере.
Обязательное условие работы: свободные экстенты в VG. Если группа томов заполнена, dmeventd не сможет расширить пул, и он всё равно упрётся в потолок. Держите 10-20% свободного места и следите за vgs -o vg_name,vg_free.
Организация внешнего мониторинга и алертов
Собирайте метрики раз в минуту и отправляйте их в Prometheus через textfile collector node_exporter либо в Zabbix через UserParameter.
#!/bin/sh
POOL=vg_data/pool
OUT=/var/lib/node_exporter/textfile_collector/lvm_thin.prom
DATA=$(lvs --noheadings -o data_percent "$POOL" | tr -d ' ')
META=$(lvs --noheadings -o metadata_percent "$POOL" | tr -d ' ')
{
echo "lvm_thin_data_percent{pool=\"$POOL\"} $DATA"
echo "lvm_thin_metadata_percent{pool=\"$POOL\"} $META"
} > "$OUT.tmp"
mv "$OUT.tmp" "$OUT"
Правило алерта на 80% данных:
- alert: LvmThinPoolDataHigh
expr: lvm_thin_data_percent > 80
for: 10m
labels:
severity: warning
annotations:
summary: "Thin pool {{ $labels.pool }} заполнен на {{ $value }}%"
Для Zabbix хватит двух пользовательских параметров:
UserParameter=lvm.thin.data_percent[*],lvs --noheadings -o data_percent "$1" | tr -d ' ' UserParameter=lvm.thin.metadata_percent[*],lvs --noheadings -o metadata_percent "$1" | tr -d ' '
Дополнительно мониторьте свободные экстенты в VG и журнал ядра: строки device-mapper про thin появляются в dmesg раньше, чем сервисы начнут падать.
Восстановление после переполнения thin pool
Порядок действий зависит от того, что закончилось: данные или метаданные. В обоих случаях сначала прекращают запись, потом расширяют. Перезагрузка сервера проблему не решает: места в пуле от неё не прибавляется, а автоматическая активация пула после сбоя metadata может не пройти.
Диагностика: как понять, что thin pool переполнен
- Приложения пишут ошибки ввода-вывода и No space left on device, хотя df показывает свободное место в файловой системе. Это классический признак исчерпанного пула.
- В dmesg есть строки от device-mapper про thin, сообщения о достижении порога (low water mark) и о переводе пула в режим только для чтения.
- lvs показывает data_percent или metadata_percent около 100.
dmesg -T | grep -i -E 'thin|device-mapper' | tail -n 30 lvs -a -o lv_name,lv_attr,lv_size,data_percent,metadata_percent vg_data vgs -o vg_name,vg_free_count,vg_free
Столбец lv_attr у пула обычно выглядит как twi-aotz--. Если второй символ сменился с w на r, том стал доступен только для чтения: так ведёт себя пул с исчерпанными metadata.
Аварийное расширение пула данных
- Остановите нагрузку, которая пишет в тома: выключите виртуальные машины, остановите сервисы, переведите базы в режим только для чтения.
- Освободите неиспользуемые блоки. Если пул принимает discards, поможет fstrim -av: освобождение блоков сразу уменьшит data_percent. Режим виден в lvs -o lv_name,discards vg_data/pool, включается командой lvchange --discards passdown vg_data/pool.
- Проверьте свободные экстенты: vgs -o vg_name,vg_free.
- Расширьте данные пула.
lvextend --size +100G vg_data/pool
- Убедитесь в результате: lvs -o lv_name,lv_size,data_percent vg_data/pool.
Если в VG нет свободного места, добавьте диск:
pvcreate /dev/sdd vgextend vg_data /dev/sdd lvextend --size +100G vg_data/pool
Команда lvextend для пула по умолчанию увеличивает именно data. Чтобы расширить metadata, нужен отдельный флаг: lvextend --poolmetadatasize +2G vg_data/pool. После расширения данных записи обычно возобновляются без размонтирования, но приложения, уже получившие ошибки ввода-вывода, придётся перезапустить.
Восстановление при переполнении metadata
Metadata - самая хрупкая часть пула. Когда место в tmeta заканчивается, ядро не может записать новые соответствия блоков и переводит пул в аварийный режим. Порядок шагов такой:
- Убедитесь, что в VG есть свободные экстенты: vgs -o vg_name,vg_free.
- Расширьте metadata.
lvextend --poolmetadatasize +2G vg_data/pool lvs -a -o lv_name,metadata_percent vg_data
- Если пул остался в режиме только для чтения, обновите таблицу устройства: lvchange --refresh vg_data/pool. Когда тома размонтированы, доступен полный цикл: vgchange -an vg_data, затем vgchange -ay vg_data.
- Проверьте, что запись идёт: в dmesg нет новых сообщений про thin, mount показывает rw, Meta% ниже 100.
Если metadata повреждены и thin_check находит ошибки в дереве, нужен ремонт. LVM умеет выполнить его на резервном metadata-томе:
lvconvert --repair vg_data/pool
Условия: пул деактивирован, в VG есть запасной metadata-том и достаточно свободного места. Ремонт может выбросить повреждённые записи о размещении блоков, и часть файлов в тонких томах пропадёт. Перед ремонтом нужна копия данных за пределами пула, после ремонта обязательна проверка файловых систем. Набор требований зависит от версии LVM, вывод lvconvert --repair --help стоит прочитать до запуска.
Ручной вариант использует утилиты thin_repair из пакета thin-provisioning-tools. Проверять и ремонтировать metadata разрешено только на деактивированном пуле, на активном запускать thin_check нельзя.
vgchange -an vg_data thin_check /dev/vg_data/pool_tmeta thin_repair -i /dev/vg_data/pool_tmeta -o /dev/vg_data/pool_tmeta_new
Проверка целостности тонких томов
После восстановления проверьте файловые системы. Для ext4:
umount /srv/vm100 fsck.ext4 -f -y /dev/vg_data/vm100
Для XFS:
umount /srv/vm100 xfs_repair -n /dev/vg_data/vm100 xfs_repair /dev/vg_data/vm100
xfs_repair работает только с размонтированным томом. Флаг -n даёт проверку без изменений и показывает, нужен ли ремонт. Флаг -L обнуляет журнал и приводит к потере последних записей, применять его стоит лишь тогда, когда без него ремонт не проходит. Через сутки после восстановления сверьте data_percent и metadata_percent, просмотрите dmesg на новые ошибки и убедитесь, что алерты молчат.
Типичные ошибки и рекомендации по эксплуатации
Ошибки при создании и настройке thin pool
- Минимальный metadata. Пул на 2 ТиБ с metadata 16 МиБ закончится по метаданным задолго до данных. Считайте 0,1% от объёма данных и добавляйте запас на снапшоты.
- Полностью заполненная VG: авторасширение без свободных экстентов бесполезно.
- Мелкий chunk при большой ферме снапшотов. Каждый снапшот требует записей в btree, и metadata растёт быстрее.
- Отключённый pool metadata spare (--poolmetadataspare n). Автоматический ремонт через lvconvert --repair станет невозможен.
- Переподписка без плана. Коэффициент 5x и выше допустим, когда есть мониторинг и свободные диски под расширение, иначе это лотерея.
- Тонкие тома под базы данных с постоянным ростом записи и без алертов: переполнение случится ночью, когда никто не смотрит.
Похожие грабли разобраны на примере ZFS в статье про типичные ошибки при работе с пулом ZFS: недооценка служебных структур, отсутствие мониторинга и надежда на «и так работает» дают одинаковые последствия в обеих системах.
Ошибки при мониторинге и восстановлении
- Смотрят только data_percent и забывают про metadata_percent.
- Ждут 100% вместо алертов на 80% и 70%.
- Расширяют metadata командой lvextend -L, которая на деле увеличивает data, а tmeta остаётся заполненной.
- Запускают thin_check и thin_repair на активном пуле и получают ошибки чтения или порчу дерева.
- Делают lvconvert --repair без резервной копии, а потом ищут пропавшие файлы.
- Перезагружают сервер вместо расширения пула.
- Игнорируют dmesg и journalctl -u dm-event.
Снапшот внутри того же thin pool не считается резервной копией. Он живёт в тех же чанках и исчезнет вместе с пулом. Копию выносите на отдельный носитель или в другое хранилище.
Режим работы, который снижает число аварий: fstrim по расписанию на всех тонких томах, discards passdown, авторасширение с порогом 80%, внешние алерты поверх него, проверка восстановления на стенде раз в квартал и runbook с точными командами.
Заключение
LVM thin provisioning экономит место и делает снапшоты почти бесплатными, но требует дисциплины: считать metadata, следить за двумя процентами, держать запас в VG и хранить копии за пределами пула.
Чек-лист развёртывания:
- PV и VG созданы, свободных экстентов не меньше 10-20%.
- Пул создан с явным --poolmetadatasize (0,1% от данных, минимум 1 ГиБ), chunk size выбран под характер нагрузки.
- dmeventd работает, в lvm.conf заданы thin_pool_autoextend_threshold = 80 и thin_pool_autoextend_percent = 20.
- data_percent и metadata_percent собираются в мониторинг, алерты на 80% и 70%, критические на 90% и 85%.
- fstrim по расписанию, discards passdown включён.
- Резервные копии лежат вне пула, восстановление проверено.
- Есть runbook: диагностика по dmesg и lvs, расширение data через lvextend, расширение metadata через --poolmetadatasize, thin_check и fsck.
- pool metadata spare не отключён.
Запускайте переподписку только там, где рядом есть свободные диски и работающие алерты. Тонкий пул прощает экономию места, но не прощает невнимательности.