среда, 19 сентября 2012 г.

Анатомия ZFS часть I

При написании данного цикла статей использовался документ ZFS On-Disk Specification,Sun Microsystems

Введение

Давным-давно, в далекой-предалекой галактике, была создана новая файловая система. И поскольку была она создана в далеком будущем, была она 128-битной, то есть емкость ее превышала квантовый порог системы хранения, базирующейся на планете Земля. И была она всегда целостной – поскольку в будущем использовались только транзакционные семантики файловых систем, и не выключалось питание у серверов, и был забыт fsck как страшный сон. Всегда сходились у этой файловой системы контрольные суммы, и никогда не угрожали бэды секторам дисков. И даже диски уже не были дисками, а давно стали твердотельными устройствами вообще без круглых и движущихся частей.

И не разделялись системы хранения на тома, но соединялись, так как множились и множились данные, подлежащие хранению. Так как не было у нее частей, но частью целого являлось каждое устройство.

Обладала новая файловая система свойствами самовосстановления данных, репликации в реальном времени, и не было войн клонов, поскольку неисчислимо их возможное количество - 264. Даже темная сторона Силы не могла уничтожить данные, ибо не властны были над файловой системой ни кувалда, ни дрель, ни световой меч джедая.

Шесть лет работал над файловой системой Джефф Бонвик (Jeff Bonwick), а на седьмой год отдыхал, поскольку увидел он, что его файловая система хороша.

И состояла новая файловая система из семи частей, поскольку семь – число угодное богам, и назывались эти семь частей – SPA (Storage Pool Allocator), DSL (Dataset and Snapshot Layer), DMU (Data Management Unit), ZAP (ZFS Attribute Processor), ZPL (ZFS Posix Layer), ZIL (ZFS Intent Log) и ZVOL (ZFS Volume).

1.     Детали устройства и принципы работы ZFS

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

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

Для повседневной практической работы с ZFS знание ее теоретических основ или хотя бы деталей устройства не является безусловно необходимым. Однако при выполнении более продвинутых задач, таких, как оптимизация производительности, или восстановление данных при разрушении дисков – понимание хотя бы основных принципов работы весьма важно и является залогом успеха.



1.1                         Виртуальные устройства, метки виртуальных устройств и загрузочный блок

В основе любой файловой системы лежат устройства хранения, которые должны быть представлены на уровне программной абстракции операционной системе.
Для ZFS первым уровнем абстракции являются пулы или пулы хранения.
Пулы хранения представляют собой совокупность одного или более дисков, в терминах ZFS называемых виртуальными устройствами (vdevs).
В ZFS cуществует два типа виртуальных устройств – физическое виртуальные устройства* (иногда их называют листовыми виртуальными устройствам – leaf vdevs) и логические виртуальные устройства (иногда называемые внутренними виртуальными устройствами – interior vdevs).
Говоря простым языком, физическое виртуальное устройство – это физическое блочное устройство с возможностью записи на него, например, жесткий диск. В свою очередь, логическое виртуальное устройство – это совокупность физических виртуальных устройств. Можно сказать, что виртуальные устройства образуют двухуровневую иерархию, где физические виртуальные устройства являются атомарными, а логические представляют собой группировки физических устройств.
Виртуальные устройства образуют дерево, где все физические виртуальные устройства являются листьями. Каждый пул имеет логическое виртуальное устройство, называемое «корневым» устройством, или вершиной дерева физических устройств.
Все прямые потомки корня дерева устройств называются виртуальными устройствами верхнего уровня. На Рис.1 иллюстрируется схема зеркального пула, состоящего из двух зеркал M1 и M2, содержащих по два диска, собранных в страйп. Зеркало М1 состоит из двух дисков vdev A и vdev B, соответственно, зеркало M2 состоит из устройств vdev C и vdev D. Зеркала M1 и M2 являются виртуальными устройствами верхнего уровня,  порожденными из корня дерева устройств,устройства vdev A, B, C и D являются физическими виртуальными устройствами соответственно.
Рис.1. Дерево устройств пула хранения

Таким образом, любой пул ZFS образует, как минимум, двухуровневую иерархию виртуальных устройств, часть из которых является реальными (физическими) устройствами, а часть логическими.

Справедливости ради следует заметить, что сходную логику организации имеют и RAID-массивы. Однако, как будет описано ниже, принципиальная разница между RAID и ZFS состоит в том, что в RAID метаданные, описывающие физическую структуру массива, хранятся отдельно от файловых систем (разделов), а ZFS хранит эти данные как часть метаданных файловой системы с многократным дублированием (описано в следующей главе). При таком подходе к основополагающей структуре ZFS позволяет проделывать различные шалости над файловыми системами, пулами и устройствами, принципиально недопустимые в RAID (описывается во второй части).
Дерево устройств пулов хранения ZFS и их свойства можно легко посмотреть командой zdb:
root @ pegasus / # zpool status
  pool: data
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        data        ONLINE       0     0     0
          c1d1      ONLINE       0     0     0

errors: No known data errors

  pool: rpool
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          c0d0s0    ONLINE       0     0     0

errors: No known data errors

root @ pegasus / # zdb
data
    version=15
    name='data'
    state=0
    txg=244656
    pool_guid=11323518611242904168
    hostid=923910478
    hostname='pegasus'
    vdev_tree
        type='root'
        id=0
        guid=11323518611242904168
        children[0]
                type='disk'
                id=0
                guid=11214377062774219052
                path='/dev/dsk/c1d1s0'
                devid='id1,cmdk@AVBOX_HARDDISK=VB4a9ca77f-8766c62b/a'
                phys_path='/pci@0,0/pci-ide@1,1/ide@1/cmdk@1,0:a'
                whole_disk=1
                metaslab_array=23
                metaslab_shift=27
                ashift=9
                asize=21461467136
                is_log=0
                DTL=28
rpool
    version=15
    name='rpool'
    state=0
    txg=125838
    pool_guid=7993308548910914564
    hostid=923910478
    hostname='pegasus'
    vdev_tree
        type='root'
        id=0
        guid=7993308548910914564
        children[0]
                type='disk'
                id=0
                guid=1589146460850643490
                path='/dev/dsk/c0d0s0'
                devid='id1,cmdk@AVBOX_HARDDISK=VB1018c62f-c4b725b9/a'
                phys_path='/pci@0,0/pci-ide@1,1/ide@0/cmdk@0,0:a'
                whole_disk=0
                metaslab_array=24
                metaslab_shift=27
                ashift=9
                asize=17136615424
                is_log=0
                DTL=99

При помощи команды zdb мы получили описание вершины деревьев витруальных устройств, в котором для каждого пула хранятся вершинные данные пулов и деревьев виртуальных устройств, которые представляют из себя следующее:
version – Версия пула, текущая 15.
name – Имя пула, которому принадлежат устройства.
state – состояние пула, возможные состояния: 0 – Active, 1 – Exported, 2 – Destroyed.
txg – Транзакционная группа, для которой в последний раз была записана метка диска.
pool_guid – Глобальный уникальный идентификатор пула.
hostid и hostname идентификатор и имя хоста, которому принадлежит пул соответственно.

Vdev_tree содержит глобальный идентификатор дерева устройств, каждое виртуальное устройство также содержит собственный уникальный guid.

Описатель children определяет каждое виртуальное устройство и содержит следующую группу данных:

type – Тип виртуального устройства. Могут быть определены следующие типы устройств:
1.     «disk» - блочное устройство
2.     «file» - файловое устройство
3.     «mirror» - часть зеркала
4.     «raidz» - часть raidz
5.     «replacing» - заменяемая часть зеркала
6.     «root» - корень дерева виртуальных устройств

id – Индекс устройства в массиве родительского дерева (в приведенном примере 0, что совпадает с индексом родительского описателя children).
path – путь устройства, определяется только для листовых устройств.
Признак whole_disk показывает, является ли виртуальное устройство слайсом (с меткой SMI) или целым диском (с меткой EFI).
metaslab_array и metaslab_shift содержат сводные данные структуры метаслабов (будут рассмотрены позднее), assize содержит объем пространства, распределенный на вершине виртуального устройства.
Атрибут is_log определяет, является ли устройство журнальным (выделено под ZIL).

(продолжение следует)



* Забавно, что сам термин «физическое виртуальное устройство» (physical virtual device) является оксюмороном, так как состоит из двух взаимоисключающих терминов. По логике, устройство может быть либо физическим либо виртуальным. Однако данный термин употребляется в документации Sun/Oracle именно в подобной форме.