Место на диске рано или поздно заканчивается, и классический раздел с этим ничего поделать не может: чтобы увеличить его, приходится останавливать сервисы, пересоздавать таблицу разделов или переносить данные на новый носитель целиком. Диспетчер логических томов LVM (Logical Volume Manager) решает эту проблему иначе: он добавляет между физическими дисками и файловой системой промежуточный слой абстракции, который позволяет объединять несколько накопителей в единое пространство и расширять его без остановки сервисов и без переразметки диска в привычном понимании.

Три уровня абстракции, из которых состоит LVM

Прежде чем набирать команды, стоит разобраться в терминологии, потому что путаница между уровнями это главная причина ошибок у новичков. Физический том (PV, Physical Volume) это диск или раздел, размеченный под работу с LVM, и именно с него начинается инициализация. Группа томов (VG, Volume Group) объединяет один или несколько физических томов в общий пул пространства, из которого потом нарезаются логические тома. Логический том (LV, Logical Volume) это уже тот объект, поверх которого создаётся файловая система и с которым работают приложения, будто это обычный раздел диска. Схематично цепочка выглядит так: физические диски становятся физическими томами, физические тома объединяются в группу томов, а группа томов нарезается на логические тома произвольного размера в пределах общего пула.

Диск для LVM не обязан быть физическим устройством целиком, вполне допустимо инициализировать под LVM отдельный раздел диска, оставив остальное пространство под другие нужды. На практике администраторы расходятся во мнениях, что удобнее: инициализировать физический том прямо на весь диск целиком (pvcreate /dev/sdb) или на конкретный раздел (pvcreate /dev/sdb1). Разница на практике минимальна, кроме одного нюанса: если LVM занял весь диск без разметки на разделы, а позже понадобится выделить часть этого диска под что то другое, сделать это будет уже нельзя, зато при работе через раздел теряется около 1 мегабайта пространства из за стандартного выравнивания таблицы разделов, поскольку современные fdisk и parted по умолчанию начинают первый раздел не с самого начала диска, а с сектора 2048, оставляя начальный мегабайт под служебные структуры и корректное выравнивание под физический размер сектора. Жёсткого правила тут нет, но раздел считается более гибким и предсказуемым решением на будущее.

Подготовка дисков и создание физических томов

Перед тем как объединять несколько дисков, каждый из них нужно пометить как физический том командой pvcreate. Если в системе есть три новых диска /dev/sdb, /dev/sdc и /dev/sdd, которые нужно объединить в общее пространство, команды инициализации выглядят так:

pvcreate /dev/sdb
pvcreate /dev/sdc
pvcreate /dev/sdd

Команда записывает в начало каждого диска дескриптор группы томов и служебные метаданные LVM, после чего диск становится видимым для остальных утилит комплекта. Проверить результат можно командой pvdisplay, которая покажет размер каждого тома, его уникальный идентификатор и текущий статус: занят том какой то группой томов или ещё свободен. Размер области метаданных на физическом томе при необходимости задаётся отдельно через параметр -–metadatasize, но для большинства сценариев подходит значение по умолчанию.

Объединение дисков в единую группу томов

Как только физические тома готовы, их объединяют в группу командой vgcreate, указывая произвольное имя группы и список всех входящих в неё устройств:

vgcreate data-vg /dev/sdb /dev/sdc /dev/sdd

После выполнения команды три отдельных физических диска превращаются в единый пул дискового пространства с общим именем data-vg. Посмотреть суммарный размер группы и список входящих в неё физических томов позволяет команда vgdisplay: поле VG Size покажет общий объём всех трёх дисков вместе, что и является главным практическим смыслом объединения, а поле VG Name подтвердит принадлежность каждого физического тома к нужной группе. Если позже появится четвёртый диск, его можно будет добавить в существующую группу командой vgextend, не трогая уже созданные логические тома и не прерывая работу файловой системы.

Создание логического тома поверх объединённого пространства

Группа томов сама по себе не используется приложениями напрямую, из неё нужно нарезать логический том, который уже и получит файловую систему. Задать размер тома можно двумя способами: точным значением через параметр -L или долей от общего свободного пространства группы через параметр -l. Пример создания тома фиксированного размера:

lvcreate -L 500G -n bigdata data-vg

Здесь -L 500G задаёт объём в 500 гигабайт, а -n bigdata присваивает логическому тому имя. Если цель забрать под том всё доступное пространство группы без остатка, команда меняется на использование ключа -l с указанием процента:

lvcreate -l 100%FREE -n bigdata data-vg

После создания том становится доступен по пути вида /dev/data-vg/bigdata, и именно этот путь используется дальше при создании файловой системы и монтировании. Проверить получившиеся параметры позволяет команда lvdisplay, которая покажет путь к устройству в поле LV Path, имя тома в поле LV Name и фактический размер выделенного пространства.

Полосатые тома для распределения нагрузки между дисками

Отдельного внимания заслуживает режим полосатого логического тома (striped), при котором операции чтения и записи распределяются сразу по нескольким физическим дискам группы, похоже на то, как работает RAID0. Такой режим задаётся параметром --stripes при создании тома:

lvcreate --extents 100%FREE --stripes 3 --name data-lv01 data-vg01

Команда создаёт один логический том, охватывающий всю группу томов data-vg01 и распределяющий данные по трём физическим дискам одновременно. Смысл этого приёма в производительности: без полосования операции ввода-вывода обращаются последовательно к тем физическим томам, где физически размещены нужные данные, а с полосованием нагрузка равномерно расходится по всем подключённым дискам данных, что особенно заметно на серверах с интенсивным параллельным доступом к файлам.

У полосатых томов есть отдельное правило, которое стоит знать заранее, ещё до создания такого тома. Расширить полосатый том в будущем одним новым диском не получится: LVM по умолчанию наследует параметры чередования последнего сегмента тома, и если данные изначально были размазаны по трём физическим дискам, для продолжения того же чередования группе томов потребуется добавить сразу три новых диска с достаточным местом на каждом, а не один. Попытка расширить такой том, добавив в группу лишь один диск, завершится ошибкой нехватки места для размещения нужного числа сегментов, даже если суммарного свободного пространства в группе формально достаточно. Обойти ограничение технически можно, принудительно записав новый участок тома линейно через дополнительный ключ у lvextend, но тогда часть тома, добавленная таким способом, не получит прироста производительности от чередования и будет работать как обычный линейный том. Из за этой особенности полосатые тома оправданы там, где заранее известно, что группа томов будет расширяться сразу партиями одинакового числа дисков, а не по одному накопителю за раз.

Файловая система поверх логического тома

Логический том без файловой системы бесполезен для хранения обычных файлов, поэтому следующим шагом на него ставится нужная файловая система стандартными утилитами, будто это обычный раздел диска:

mkfs.ext4 /dev/data-vg/bigdata
mount /dev/data-vg/bigdata /mnt/data

Для XFS команда форматирования выглядит как mkfs.xfs вместо mkfs.ext4, а дальнейшее монтирование ничем не отличается. Выбор между ext4 и XFS напрямую влияет на то, какими средствами том можно будет расширять и, что важнее для крупных хранилищ, можно ли будет его когда либо уменьшать: у XFS такой возможности штатно нет, тогда как ext4 поддерживает и увеличение, и уменьшение размера файловой системы.

Расширение тома на лету без остановки сервисов

Главное практическое преимущество LVM перед классической разметкой дисков это способность расширять пространство без размонтирования файловой системы и без остановки приложений, которые с ней работают. Процесс состоит из двух независимых шагов: сначала увеличивается сам логический том, а затем под новый размер подгоняется файловая система поверх него.

Если группа томов уже располагает свободным пространством, например после добавления нового физического диска командой vgextend, логический том расширяется командой lvextend:

lvextend -l +100%FREE /dev/data-vg/bigdata

Ключ -l +100%FREE забирает под указанный том всё оставшееся свободное место группы. Для расширения на конкретный объём вместо процента указывается величина напрямую, например lvextend -L +200G для добавления именно двухсот гигабайт к текущему размеру тома. После расширения самого тома файловая система внутри него по прежнему видит старый, меньший размер, пока её явно не растянуть под новые границы.

Для файловой системы ext4 растягивание выполняется командой resize2fs:

resize2fs /dev/data-vg/bigdata

Для XFS применяется другая утилита, xfs_growfs, и в отличие от resize2fs ей передаётся не путь к устройству, а точка монтирования файловой системы:

xfs_growfs /mnt/data

Обе команды умеют работать с уже смонтированной и активно используемой файловой системой, поэтому весь цикл "добавили диск, расширили группу, расширили том, растянули файловую систему" проходит без единой перезагрузки и без остановки приложений, читающих или пишущих данные в этот момент на диск. Утилита lvextend поддерживает и сокращённую запись всей цепочки одной командой через ключ -r, который автоматически вызывает resize2fs или xfs_growfs сразу после изменения размера тома:

lvextend -r -l +100%FREE /dev/data-vg/bigdata

Порядок действий при добавлении нового диска в существующую группу

Расширение растущего хранилища новым физическим диском требует последовательного прохода через все уровни абстракции LVM, и пропуск любого шага приведёт к тому, что новое пространство останется недоступным приложениям. Ниже описан сценарий для обычного линейного тома без чередования; для полосатого тома из предыдущего раздела вместо одного диска потребуется сразу добавить в группу число дисков, кратное исходному количеству полос:

  1. Подключить новый диск к серверу и убедиться, что система видит его командой lsblk или fdisk -l;
  2. Инициализировать диск как физический том командой pvcreate /dev/sdX, где sdX это имя нового устройства;
  3. Добавить полученный физический том в существующую группу командой vgextend data-vg /dev/sdX, после чего свободное пространство группы увеличится на объём нового диска;
  4. Расширить нужный логический том командой lvextend с указанием желаемого объёма или ключа +100%FREE для использования всего нового пространства;
  5. Растянуть файловую систему под новый размер тома командой resize2fs для ext4 или xfs_growfs для XFS, передав команде соответствующий путь к устройству или точку монтирования.

Особые случаи и ограничения, о которых нужно знать заранее

Уменьшение логического тома работает совсем иначе, чем расширение, и требует куда большей осторожности. Для файловой системы ext4 порядок действий полностью обратный: сначала выполняется проверка целостности командой e2fsck, затем файловая система уменьшается командой resize2fs до нужного меньшего размера, и только после этого можно безопасно уменьшать сам логический том командой lvreduce, причём такая операция чаще всего требует предварительного размонтирования файловой системы, в отличие от расширения, которое проходит на лету без прерывания работы. Файловая система XFS вообще не поддерживает уменьшение штатными средствами: разработчики принципиально не реализовали эту функцию из за сложности безопасного освобождения места в структуре хранения XFS, и единственный рабочий вариант уменьшить занимаемое пространство это перенести данные на новый, заведомо меньший том и удалить старый.

Если LVM используется не поверх целого диска, а поверх стандартного раздела внутри таблицы разделов, перед расширением логического тома придётся сначала увеличить сам раздел утилитой growpart или через ручное пересоздание записи в таблице разделов с последующим уведомлением ядра командой partprobe, и только затем выполнять pvresize, чтобы физический том осознал появившееся дополнительное пространство внутри увеличенного раздела. Забытый на этом этапе вызов partprobe или pvresize оставит логический том прежнего размера даже после успешного расширения раздела на уровне диска, и новое пространство просто повиснет неиспользуемым до следующей перезагрузки или ручного вмешательства.

Расширение корневого раздела системы через LVM заслуживает отдельного упоминания, поскольку именно этот сценарий чаще всего пугает начинающих администраторов необходимостью загрузки с внешнего носителя. На практике при использовании LVM корневой раздел растягивается тем же набором команд lvextend и resize2fs или xfs_growfs прямо во время работы системы, без перезагрузки и без livecd, что и остаётся одним из главных практических аргументов в пользу LVM при первоначальной разметке серверов, которые в будущем предположительно будут расти по объёму хранимых данных.

Контроль состояния группы и логических томов после изменений

После любой операции расширения разумно убедиться, что размеры действительно изменились так, как задумано, а не остановились на промежуточном шаге. Команда vgs выводит сжатую таблицу по всем группам томов в системе сразу с несколькими колонками: общий размер группы, объём свободного пространства, оставшегося после всех выделений, и количество входящих в группу физических томов. Аналогичная по духу команда lvs показывает такую же сводку уже по логическим томам: имя тома, принадлежность к группе, текущий размер и процент заполнения, если на томе включено отслеживание использования, например для снимков состояния.

Отдельно стоит проверять реальный размер файловой системы командой df -h, а не только вывод lvdisplay или lvs, потому что размер логического тома и размер файловой системы внутри него это два разных числа. Расширение логического тома без последующего вызова resize2fs или xfs_growfs оставит файловую систему в прежних границах, и новое пространство физически будет выделено под том, но окажется недоступным приложениям, пока администратор не завершит второй шаг растягивания. Именно рассинхронизация этих двух чисел чаще всего сбивает с толку тех, кто впервые работает с LVM: команда lvextend отработала без ошибок, размер тома в выводе lvs вырос, а свободного места в df -h по прежнему не прибавилось.

Перед плановым расширением на боевых серверах полезно заранее посмотреть тип используемой файловой системы командой df -T, чтобы не перепутать команду растягивания и не запустить resize2fs на разделе с XFS, где эта утилита просто откажется работать с понятным сообщением об ошибке. Такая проверка занимает секунду, но избавляет от лишней паузы в процессе обслуживания сервера, когда расширение уже начато, а сервисы продолжают писать данные в исходный, ещё не увеличенный логический том.