Введение
В данной статье рассмотрены принципы и методики по применению снапшотов. Для более лучшего понимания материала необходимо знать, что такое LVM на базовом уровне и уметь оперировать с PV, VG, LV.
Назначение и принцип работы снапшотов
Снапшоты отчасти относятся к системам резервного копирования, но по сути не являются бэкапом, а лишь позволяют возвращать данные в исходное состояние на определенный момент времени. Так, когда необходимо сделать полный бэкап (например, сервера с активной базой данных), понадобится останавливать запись на диск и только потом снимать копию, т.к. в противном случае не все данные попадут в копию. Вариант с наличием slave-базы в счёт не берется, т.к. это частный случай ещё одной возможности для создания резервной копии. При больших объемах копирование может занимать несколько часов и более, что недопустимо для production-систем, работающих 24\7 – ведь никто не останавливает боевую базу для снятия дампа.
В таких случаях при необходимости создания полной копии без остановки на запись (почти) и приходят на помощь снапшоты. При создании снапшота происходит моментальный снимок или “заморозка” данных. Процесс создания снимка происходит, как правило, очень быстро – приложение или операционная система на какое-то непродолжительное время приостанавливает запись, и в этот момент создается моментальный снимок текущего состояния данных. Под приостановкой записи подразумевается, что приложение будет работать, но процессы записи на диск осуществляться не будут. Для клиента это может выглядеть как некая кратковременная задержка. Длительность такой задержки будет зависеть от приложения и его размера.
COW (Copy-On-Write)
Итак, разобравшись, что такое снапшот и когда он применяется, необходимо понимать, что происходит с файлами после создания снимка. Снапшот создан, и все старые файлы, т.е. которые не изменялись на момент создания снимка, остались на месте. А вот новые файлы или изменения для существующих уже будут записаны в новое расположение файловой системы на диске. Даже когда модификация данных завершена, старые данные никогда не перезаписываются. По сути будет создан ещё один файл, в котором содержатся все изменения (дельта), которые происходят с исходными данными. Таким образом достигается экономия дискового пространства засчет хранения лишь изменений на диске, а не полной копии данных. Технически происходит следующее: при необходимости изменения старого файла создается reflink и выделяется место под изменения.
Поэтому есть общие рекомендации и напоминания относительно снапшотов:
- Снапшот – не бэкап!
- Не стоит хранить снапшоты длительное время, особенно в продакшене. Снапшот выполнил свою функцию и должен быть сразу удален.
- Не стоит хранить большое дерево снапшотов (2-3 штуки будет достаточно), в противном случае производительность диска значительно просядет.
LVM
По большей части со снапшотами приходится сталкиваться при работе с виртуальными машинами. И действительно, очень удобно бывает сделать снимок виртуалки, провести эксперимент и откатиться на снапшот в случае неудачи. Но возможность создания снапшотов также присутствует и в LVM – когда-то давно я описывал базовые принципы работы LVM в своей статье. Теперь же будет рассмотрен дополнительный функционал по работе со снапшотами.
LVM1 vs LVM2
Перед продолжением, стоит кратко упомянуть, что существуют две версии – LVM1, которая имеет несколько отличий от LVM2. Самым главным отличием является следующее:
- если блок должен быть изменен в источнике, он сначала копируется в моментальный снимок (снапшот), помечается как скопированный в таблице исключений, а затем новые данные записываются в исходный том. Так работает LVM1, снимки которого являются readonly.
- LVM2 позволяет создавать снимки для чтения и записи, т.е. работает схожим образом, как и LVM1, но при необходимости записи данных в самом снапшоте, блоки данных помечаются в таблице исключений как используемые и уже никогда не будут скопированы с исходного тома.
Под таблицей исключений понимается хеш-таблица, в которой записываются все сопоставления относительно изменений блоков и таблицы CoW. Но это уже глубокие технические подкапотные детали, с которыми можно ознакомиться по ссылке.
В целом обе версии можно использовать, но у второй есть несомненное преимущество в виде возможности изменений в самом снапшоте.
Пример использования
Подготовительные работы
После того, как с теорией разобрались, пора переходить к практике! В качестве лабораторного стенда будет использоваться Centos 7 с установленным пакетом lvm2:
yum install lvm2
- PV: sdb1 5 Гб
- VG: vg_data 5 Гб
- LV: lv_data 2,5 Гб
- точки монтирования: /mnt и /mnt2
Отличительной особенностью является то, что для создания снапшота в VG должно быть свободное пространство, которое будет использоваться для записи изменений, т.е. это место будут занимать изменяемые данные в исходном томе, которые “доезжают” уже после создания снапшота. Поэтому в качестве примера был создан LV размером 2,5 Гб, а остальное пространство осталось неиспользованным:
vgs
VG #PV #LV #SN Attr VSize VFree
vg_data 1 1 0 wz--n- <5.00g 2.50g
Далее LV был смонтирован по пути /mnt, и туда записаны произвольные файлы:
df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 454M 0 454M 0% /dev
tmpfs 464M 6.8M 457M 2% /run
tmpfs 464M 0 464M 0% /sys/fs/cgroup
/dev/sda3 19G 4.5G 14G 26% /
/dev/sda1 190M 136M 41M 78% /boot
/dev/mapper/vg_data-lv_data 2.5G 135M 2.4G 6% /mnt
echo "test record" >/mnt/snapshot.txt
dd if=/dev/zero of=/mnt/test_file bs=512M count=1 oflag=dsync
Команда ниже показывается, что в данный момент присутствует только один LV, готовый к работе (в выводе lvs attr есть флаг “о” – open):
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data -wi-ao---- <2.50g
Создание снапшота
Для создания снапшота достаточно выполнить команду ниже. Используется lvcreate, т.к. снапшот по сути является LV, но особенностью является то, что необходимо указать размер, куда будут записываться изменения. Для этого должно быть свободное место в VG, в данном случае из доступных 2,5 Гб указывается 1 Гб и наименование снапшота – snap_vg_data:
lvcreate -L 1G -s -n snap_vg_data /dev/mapper/vg_data-lv_data
Т.к. снапшот – это по сути LV, проверить его наличие можно командой ниже:
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data owi-aos--- <2.50g
snap_vg_data vg_data swi-a-s--- 1.00g lv_data 0.00
Как видно из команды выше, у исходного тома и снапшота появились новые атрибуты:
- Источник снапшота, т.е. указывает, что том является исходным относительно снапшота, origin
- Права на запись, writable
- Политика размещения: унаследовано от VG, inherit
- Статус, active
- Устройство: открыто или смонтировано, open
Также можно посмотреть более подробный вывод про LV или снапшот, где вся информация будет в расширенном виде:
lvdisplay /dev/vg_data/snap_vg_data
--- Logical volume ---
LV Path /dev/vg_data/snap_vg_data
LV Name snap_vg_data
VG Name vg_data
LV UUID 6J1Fxj-x5Gi-i0zh-FHhn-fwA2-A51k-wavtFv
LV Write Access read/write
LV Creation host, time node.local, 2021-05-13 14:36:37 +0300
LV snapshot status active destination for lv_data
LV Status available
# open 0
LV Size <2.50 GiB
Current LE 639
COW-table size 1.00 GiB
COW-table LE 256
Allocated to snapshot 0.00%
Snapshot chunk size 4.00 KiB
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:3
Помимо атрибутов, появилось поле Data (Allocated to snapshot в lvdisplay), которое показывает свободное место для снапшота в процентах. На данный момент весь выделенный гигабайт свободен, т.к. в исходный том в /mnt не было записано никаких изменений.
Теперь же в исходный том будут внесены изменения для демонстрации поведения снапшота:
dd if=/dev/zero of=/mnt/test_file1 bs=512M count=1 oflag=dsync
Был создан простой файл, забитый нулями, размером 512 Мб. И в lvs это изменение сразу учитывается:
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data owi-aos--- <2.50g
snap_vg_data vg_data swi-a-s--- 1.00g lv_data 50.79
Ещё одним способом для наглядной проверки использования места снапшотом является утилита dmsetup:
dmsetup status /dev/vg_data/snap_vg_data
0 5234688 snapshot 1065088/2097152 4160
В выводе выше интересны последние три цифры:
- кол-во используемых секторов
- кол-во доступных секторов
- кол-во мета секторов
При записи на исходный том количество мета секторов будет увеличиваться.
Повреждения снапшота
Может возникнуть логичный вопрос, а что произойдет, если все секторы будут использованы, и отведенный гигабайт исчерпается? Такой снапшот станет непригодным для использования. Так, если создать ещё один файл через dd и после посмотреть статус:
dd if=/dev/zero of=/mnt/test_file2 bs=512M count=1 oflag=dsync
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data owi-aos--- <2.50g
snap_vg_data vg_data swi-I-s--- 1.00g lv_data 100.00
dmsetup status /dev/vg_data/snap_vg_data
0 5234688 snapshot Invalid
…то можно увидеть, что статус снапшота теперь Inactive в выводе lvs и Invalid в dmsetup.
Такой снепшот непригоден для использования и его остаётся только удалить:
lvremove /dev/vg_data/snap_vg_data
Для предотвращения такой ситуации настоятельно рекомендуется сохранять размер снапшота таким же, как у исходного логического тома, чтобы минимизировать риск повреждения снапшота. Это можно делать в автоматическом режиме, добавив параметры в /etc/lvm/lvm.conf:
snapshot_autoextend_threshold = 70
snapshot_autoextend_percent = 20
Максимальный размер снапшота – 1 Гб. Если его размер превысит 70% от допустимого размера, то есть будет занято 700 Мб, то допустимый размер будет увеличен на 20%, т.е. 1,2 Гб и т.д. Размер моментального снимка LVM будет продолжать увеличиваться до тех пор, пока есть свободное место в VG.
Монтирование снапшота
После повреждения и удаления снапшота, необходимо создать новый уже известной командой:
lvcreate -L 1G -s -n snap_vg_data /dev/mapper/vg_data-lv_data
Но теперь для использования функционала LVM2 можно смонтировать снапшот в отдельную точку /mnt/2:
mount -o nouuid /dev/vg_data/snap_vg_data /mnt2
Если не указать флаг -o nouuid
при использовании XFS и смонтированном исходным LV (origin), то возникнет ошибка вида:
mount: wrong fs type, bad option, bad superblock on /dev/mapper/vg_data-snap_vg_data,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so.
А в syslog появится сообщение: kernel: XFS (dm-3): Filesystem has duplicate UUID 78db9895-a427-4906-b496-fbd5df8a3ca3 – can’t mount
Причина тому проста: XFS имеет UUID, которые являются уникальными идентификаторами файловой системы. Две файловые системы с одинаковым UUID не могут быть смонтированы на одном сервере. Поскольку снапшоты по сути представляют собой одну и ту же файловую систему, UUID для обоих устройств будут одинаковыми, поэтому и используется ключ nouuid при монтировании.
Теперь имеются две точки монтирования, одна из которых является снапшотом. Для примера можно внести изменения в файлах на /mnt2, а после выполнить слияние с исходным LV.
Слияние (merge) снапшота с исходным LV
Данный функционал очень удобен при выполнении различных экспериментов. Самый простой, для примера: есть софт, который меняет файлы на диске. Перед применением на продакшене, необходимо проверить, что всё будет работать корректно. Смонтированный снапшот продуктивной LV идеально подойдет для проведения эксперимента – в случае его успешности можно будет выполнить слияние с исходным томом или же просто удалить. Исходная файловая система при этом никак не пострадает. Применение данного функционала можно найти в различных случаях.
На снапшоте для некоторых файлов вносятся изменения, после чего необходимо отмонтировать исходный LV и сам снапшот:
umount /mnt
umount /mnt2
lvdisplay должен показывать, что LV том не используется и значение open равно нулю:
lvdisplay /dev/vg_data/lv_data
--- Logical volume ---
LV Path /dev/vg_data/lv_data
LV Name lv_data
VG Name vg_data
LV UUID cf06Db-ZGJy-ABmx-l111-CVx2-fXK7-6QgYOD
LV Write Access read/write
LV Creation host, time node.local, 2021-05-13 14:28:46 +0300
LV snapshot status source of
snap_vg_data [active]
LV Status available
# open 0
LV Size <2.50 GiB
Current LE 639
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:0
Теперь можно запустить слияние всех изменений из снапшота в исходный LV:
lvconvert --merge /dev/vg_data/snap_vg_data -b
Ключ -b означает запуск в фоновом режиме. Если в Attr значение “О”, значит мерж в процессе:
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data Owi-a-s--- <2.50g 0.00
Наблюдать за прогрессом изменения секторов можно через dmsetup:
watch -n 1 dmsetup status /dev/vg_data/lv_data
В конечном итоге, если слияние завершилось, атрибуты будут следующие:
lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv_data vg_data -wi-ao---- <2.50g
Если кажется, что процесс подвис, а в dmsetup не происходит изменений, то нужно убедиться, что LV том не примонтирован. Если попытаться смонтировать том, то будет ошибка Command on LV vglxc/wikisnapshot is invalid on LV with properties: lv_is_merging_cow. В таком случае можно попытаться перезапустить мерж, указав аргументом наименование VG:
lvchange --refresh vg_data
Заключение
В статье были рассмотрены теоретические аспекты назначения и применения снапшотов, а также проведены практические проверки на примере LVM2 в Centos 7. Резюмируя, стоит выделить основные моменты, о которых стоит помнить (повторюсь для закрепления):
- Снапшот – не бэкап! Удобно создавать снапшоты, проводить какие-либо действия с файлами из снапшота, а после выполнять его удаление.
- Размер моментального снимка LVM не зависит от размера исходного логического тома, так как моментальный снимок LVM занимает намного меньший размер, в то время как полноценная резервная копия занимает почти эквивалентный размер по сравнению с исходным логическим томом (в зависимости от типа сжатия).
- Снапшоты не распределяют дисковое пространство сами по себе, как связанные с ними исходные LV, потому что для снимка требуется пространство только тогда, когда исходный LV был изменен, поэтому нужно следить за свободным местом в VG.
И ремарка по целесобразности использования снапшотов в прицнипе: конечно, в чистом виде создание снапшотов так или иначе тормозит работу приложения, но по идее всего лишь на несколько секунд плюс-минус. Но в любом случае при наличии критичной highload-системы и высокого SLA, создание снапшота на работающем сервере никто выполнять не будет – как минимум, такие серверы выводят из эксплуатации (методом исключения из балансировки, например), и далее уже выполняют создание снапшота, если это необходимо, или используют иные средства. А на всех же прочих не столь критичных системах вполне допустимо появление кратковременной задержки в пару секунд при создании снапшота опять же, если такой необходимо создать – например, перед обновлением какого-либо софта.
Лично мне не доводилось использовать снапшоты LVM, т.к. обычно я пользуюсь снапшотами, которые предоставляет делать гипервизор для виртуальных машин. Принцип работы такой же, что описан в начале статьи. Но также есть серверы, доступа к которым из консоли гипервизора у меня нет, и вот тут в теории уже можно будет попробовать использовать возможности снапшотов в LVM.