Особенности работы Sparse дисков в VMware ESXi



  • Сегодня я хотел бы рассказать об особенностях архитектуры "разреженных" (Sparse) дисков, использующихся для виртуальных машин на базе гипервизора ESXi и файловой системы VMFS.

    Знание некоторых аспектов работы Sparse дисков позволит лучше понять преимущества и недостатки использования данной технологии для защиты данных (снапшоты и бекапы) или для более эффективного использования дискового пространства (Linked Clones).

    Начнем с общей теории. ESXi поддерживает различные форматы виртуальных дисков для хранения данных: VMFS, vmfsSparse, vmfsSeSparse, RDM, VVOL, vSAN.

    VMFS (также известный как FLAT) формат является самым простым, он используется для thick и thin виртуальных дисков. Виртуальный диск хранится в виде двух файлов - файла дескриптора (.vmdk) и бинарного файла с данными (-flat.vmdk).

    Пример файла дескриптора.

    # Disk DescriptorFile
    version=1
    encoding="UTF-8"
    CID=ec393eec
    parentCID=ffffffff
    createType="vmfs"

    # Extent description
    RW 4194304 VMFS "vm01-flat.vmdk"

    # The Disk Data Base
    #DDB
    ddb.adapterType = "lsilogic"
    ddb.geometry.cylinders = "261"
    ddb.geometry.heads = "255"
    ddb.geometry.sectors = "63"
    ddb.longContentID = "b67f98419cca278410ca1bd9fffffffe"
    ddb.thinProvisioned = "1"
    ddb.uuid = "60 00 C2 94 5a a7 a8 8e-d6 41 59 5b b0 06 b3 2b"
    ddb.virtualHWVersion = "14"

    Бинарный файл с данными имеет плоскую структуру, такую же как файл .dd. Сектора хранятся последовательно, нулевой сектор имеет адрес 0x0000, первый - 0x0200, второй - 0x400 и так далее.

    Поскольку thick и thin диски имеют одинаковый формат (FLAT), то отсюда следует первый нюанс - за хранение тонких дисков (Thin provisioning) отвечает файловая система VMFS (или NFS, если это поддерживается файловой системой NFS сервера). Это можно легко проверить, создав пустой тонкий диск на 1 ГБ, а затем скопирововав его на свой компьютер с файловой системой NTFS, используя File browser или SCP, скопированный файл займет 1 ГБ дискового пространства на вашем компьютере.

    Thin диск отличается от Thick диска тем, что не требует выделение всего дискового простанства при создании, а увеличивается по мере заполнения данными. Гранулярность с которой растет thin диск зависит от размера файлового блока, который использует файловая система VMFS. Для актуальных версий VMFS5 и VMFS6 размер файлового блока (в большинстве случаев) составляет 1 МБ. Это значит, что thin диск также будет прирастать сегментами по 1 МБ. Также это приводит к фрагментированности хранения файлов thin дисков на файловой системе, адресуемые сегменты thin диска могут хранится в разных частях хранилища VMFS, что может усложнить восстановление данных в случае порчи метаданных VMFS.

    Второй нюанс заключается в том, что VMFS является кластерной файловой системой с разделяемым доступом. Это означает, что несколько хостов ESXi могут одновременно записывать данные. Для координации доступа используется раздел с метаданными файловой сиситемы, в котором указывается - в какие файлы/области диска какой из хостов может выполнять запись. Каждый раз при создании или выделении нового сегмента для увеличении размера тонкого диска один из хостов блокирует том для внесения изменений в метаданные, используя SCSI-3 резервации или часть секторов, используя механизм ATS VAAI.

    Sparse диски

    Sparse диски (они же delta-диски, Redo Log файлы или снапшоты, как их называют в быту) имеют более сложную структуру по сравнению с VMFS дисками.

    Sparse диск создается "поверх" родительского диска (другого Sparse диска или базового VMFS диска). Sparse диск аккумулирует в себя все изменения (все операции записи), которые выполняются для данной цепочки, выступая т.н. Redo Log файлом, и растет по мере заполнения.

    Но Sparse диски могут использоваться и без снапшотов (те же linked clones ВМ) и даже без базового диска, например, можно создать SE Sparse диск, выполнив команду:

    vmkfstools -c 10g -d sesparse disk.vmdk

    Sparse диски в отличие от FLAT дисков являются тонкими благодаря внутреннему формату хранения данных. При копировании такого диска с VMFS он сохраняет свой реальный размер, а не раздувается как FLAT диски.

    Изначальной целью создания Sparse дисков было обеспечить максимальную экономию дискового пространства при хранении изменений. По этой причине, гранулярность хранения данных для Sparse дисков составляет 512 байт. Иными словами, если после создания снапшота на диск потребуется записать всего 10 байт данных, то внутри Sparse диска будет выделен блок размером в 512 байт. Чуть позже мы более детально рассмотрим внутренний формат хранения и механизмы работы операций чтения и записи.

    Однако, поскольку Sparse диски хранятся на файловой системе VMFS, то минимальный размер файла связан с размером файлового блока (по умолчанию, 1 МБ для VMFS5). Я намеренно опускаю ряд технических нюансов по хранению файлов маленького размера внутри файловых дискрипторов или суб-блоков, чтобы не перегружать читателей. По факту, размер прироста файла снапшота составляет 16 МБ. Умудренный читатель спросит - почему выделяемый сегмент для Sparse диска гораздо больше, чем для Thin диска (16 МБ против 1 МБ)? Я не нашел достоверной информации по этому поводу, но могу предположить, что это сделано для того, чтобы уменьшить количество блокировок VMFS, которые возникают при увеличении размера файла и необходимости выделения новых файловых блоков - Sparse диски растут гораздо быстрее, т.к. аккумулируют в себя не только запись новых блоков данных, но и изменения в блоках родительских дисков.

    Для связи родительского (parent) диска с дочерними используется механизм указателей. В каждом файле дескриптора присутствуют два поля:

    CID=ec393eec
    parentCID=ffffffff

    Поле CID содержит уникальный 32-битный идентификатор. При создании диска это поле имеет значение fffffffe, однако каждый раз, когда файл диска открывается (например, при запуске ВМ, к которой подключен данный диск) и в этот файл записываются данные, идентификатор генерируется заново. Этот механизм позволяет отследить - вносились ли изменения в диск или нет, и позволяет гарантировать целостность данных в цепочке снапшотов.

    Поле parentCID позволяет выстроить цепочку зависимостей между виртуальными дисками. При создании Sparse диска в поле parentCID задается CID-идентификатор родительского диска. У базового VMFS диска значение parentCID всегда равно 'ffffffff'.

    На картинке ниже приведен пример многоуровневого дерева снапшотов и значение идентификаторов.

    Гипервизор проверяет на соответствие значение CID в родительском диске и parentCID в дочернем. Отличия в значении говорят о том, что родительский диск был изменен после создания дочернего диска, и консистентность данных не может быть гарантирована.

    Структура Sparse диска приведена на рисунке.

    Заголовок Sparse файла (COW Header) включает в себя следующие поля:
    • magicNumber [4 байта] - хранит в себе слово COWD в ASCII формате.
    • version [4 байта] - всегда равна 1.
    • flags [4 байта] - значение равно 3.
    • numSectors [4 байта] - количество секторов базового диска.
    • grainSize [4 байта] - размер блока данных (в секторах), который используется для хранения данных (для Sparse дисков ESXi равен 1 сектору).
    • gdOffset [4 байта] - смещение с которого начинается Granular Directory, равен 4 секторам.
    • numGDEntries - кол-во GDE (равен numSectors / gtCoverage).
    • freeSector - адрес смещения следующего свободного сектора, где может размещаться GT или полезные данные.
    Рассмотрим пример заголовка Sparse диска, созданного с базового диска размером 32 МБ.

    Более детальная информация по структуре заголовка приведена в документе Virtual Disk Format 5.0.

    Sparse файлы используют двухуровневую иерархию метаданных для адресации блоков с данными:
    • L0 - Granural Directory (GD)
    • L1 - Granular Table (GT)
    GD идет следом за заголовком COW Header. GD состоит из ячеек Granural Directory Entry (каждая размером 4 байта). Ячейки GDE используются для хранения смещения (в 512 байтный секторах) по которому располагается таблица Granular Table. Ячейки GDE всегда располагаются последовательно. Адрес первой GDE ячейки указан в поле заголовка (gdOffset) и равен 4 секторам = 0x800 = 2048 байтам. Размер/количество ячеек GDE в Granular Directory зависит от максимально возможного размера Sparse диска, а также от размера блока данных, который может адресовать одна запись в таблице (gtcoverage).

    Granual Table, на которую ссылается GDE) в свою очередь состоит из 4096 ячеек Granular Table Entry, каждая из которых хранит смещение, по которому располагается блок данных размером 512 байт (Grain Data). GT создаются по мере необходимости при первой операции записи в 2 МБ диапазон данных. Размер ячейки GTE также равен 4 байтам.

    Из-за размера ячейки GDE и GTE в 4 байта (32 бита) с учетом использования 512 байт секторов можно легко посчитать максимальный размер Sparse диска = 2^32 * 512 = 2 ТБ.

    Максимальное кол-во GDE, которое может быть создано внутри файла, рассчитывается по формуле:

    GDE = numSectors * 512 Байт / 2 МБ

    Рассмотрим пример. Создадим Sparse файл и в первый сектор диска запишем '0xffffffff'. Для того, чтобы найти нужным нам блок с данными определим адрес первой GDE по смещению gdOffset (0x800). Далее из GDE определим адрес GT (0x1000). Первая ячейка GTE будет адресует первый блок Sparse диска по смещению 0x5000.

    Учтите, что сектора, которые в базовом FLAT диске идут последовательно, не обязательно будут последовательно размещаться в Sparse файле. Адрес блока данных зависит от того, когда этот блок был выделен для записи в него новых данных. Таким образом, при случайной записи вполне реальна ситуация, которая изображена на картинке.

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

    Из-за того, что в Sparse диске хранится дополнительная служебная информация, при максимальном заполнении размер Sparse диска может превышать размер FLAT диска.

    Для примера создадим Thick диск размером 2 ГБ и затем сделаем снапшот ВМ и перезапишем все блоки псевдослучайными данными в Sparse диске:

    2114560 -rw-------    1 root     root     2164269056 Oct 30 18:07 disk-000001-delta.vmdk
    2097152 -rw-------    1 root     root     2147483648 Oct 30 17:43 disk-flat.vmdk

    Размер Sparse диска больше на ~16 МБ за счет места, которое занимает заголовок, GDE и GTE ячейки.
    Операция чтения данных для Sparse дисков выполняются следующим образом. Начиная с последнего файла в цепочке, определяется ячейка GTE, которая должна адресовать блок данных. Если значение ячейки GTE равно 0, то это означает, что блок данных еще не перезаписывался и данные следует прочитать из родительского диска (другого Sparse диска или базового FLAT диска). В случае, если значение GTE равно 1, то вместо чтения блока данных по смещению возвращаются нули. Если же в GTE указано значение отличное от 0 или 1, значит, что по указанному смещению располагается блок, содержащий данные, которые будут прочитаны.

    Что касается записи, то здесь все гораздо проще. Данные всегда записываются в последний в цепочке файл. Гранулярность записи, как было сказано ранее, составляет 512 Байт.

    В документации можно встретить упоминание, что снапшоты используют механизм Copy-on-Write (COW) для хранения данных. Это запутывает многих администраторов, которые считают, что использование отдельного файла, хранящего изменения, ближе к механизму Redirect-on-Write (ROW), чем к Copy-on-Write. Sparse диски используют механизм Cow, когда выполняют запись данных меньших, чем размер сектора. Например, вам требуется записать в сектор всего 10 изменных байт. Для обеспечения целостности данных, перед тем, как выполнить запись, должен быть инициирован целый сектор, в него будут скопированы данные из родительского диска, и только после этого могут быть записаны измененные блоки данных. Отсюда и возникает термин Copy-on-Write.

    На сегодня это вся информация, которой я хотел поделиться, в следующей части я расскажу о Space Efficient Sparse дисках, которые появились в vSphere 5.1.

    При подготовке использовались следующие материалы:
    1. https://kb.vmware.com/s/article/1015180
    2. https://www.vmware.com/support/developer/vddk/vmdk_50_technote.pdf
    3. https://www.vmware.com/content/dam/digitalmarketing/vmware/en/pdf/techpaper/sesparse-vsphere55-perf-white-paper.pdf
    4. http://sanbarrow.com/vmdk-handbook.html


    http://blog.vmpress.org/2018/11/sparse-vmware-esxi.html

 

© Lightnetics 2018