ZFS в подробностях. Былое и ныне

Алексей Федорчук
13 декабря 2007 г

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

Так, имеется русский перевод официального руководства по ZFS от фирмы Sun (архив в форматах SGML, HTML и PDF). Переводы документации по использованию ZFS конкретно во FreeBSD также имеются. Наконец, поиск в русскоязычной Википедии по ключевому слову ZFS дает на удивление богатый урожай. Ну и в конце концов, запрета на обращение к тёте Мане тоже пока нет — начать можно с банального man zfs, а потом уже — смотреть на SEE ALSO.

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

Я же, как обычно, начну с исторического введения.

Говорят, что во времена далёкие, теперь почти былинные, файловых систем не было: информация на носители записывалась побитно, без всякой организации в именованные (точнее, однозначно идентифицируемые) их наборы. Собственно, такой способ записи данных применяется и ныне — например, на стриммерные ленты.

Можно обходиться без файловых систем и при записи на стандартные устройства блочного типа — винчестеры, флэшки, компакт-диски. Так, самый простой способ резервного копирования в BSD-системах — запись на CD посредством команды burncd без предварительного создания образа диска (подробности здесь). Могут не нести на себе файловой системы и встроенные накопители некоторых цифровых камер.

Однако в большинстве случаев данные на носителях блочного типа организуются в виде файлов, а файлы объединяются в файловые системы — плоские, как в древнем DOS’е, древовидные, как во всех Unix-подобных операционках, или, так сказать, «многодревные», как в Windows. Каковые могут быть созданы непосредственно на носителе как raw-устройстве, но обычно накладываются на дисковые разделы — первичные или расширенные в DOS/Windows и Linux, разделы BSD-слайсов в одноименных операционках, и так далее.

Исторически сложилось так, что одному разделу соответствовала одна файловая система — в Windows эти термины вообще выступают практически как синонимы. Соответственно, и выходить за границы несущего их устройства файловые системы не могут. И если требуется работать более чем с одной файловой системой на одном физическом накопителе (а в Unix-подобных ОС это почти всегда так), то требуется тщательный расчет дискового пространства, потребного для каждой из них. Ошибки в расчетах влекут весьма неприятные последствия, вплоть до необходимости переразбиения диска и переустановки ОС вообще.

Это одна сторона дела. Вторая же проявляется в случаях работы с несколькими физическими накопителями на одной машине. Особенно если новый носитель добавляется уже существующую систему.

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

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

Иногда это решается аппаратно — за счёт «железных» RAID-контроллеров, но это не всегда доступно и нередко неудобно. Потому для решения этой проблемы программными средствами были разработаны промежуточные механизмы управления разделами (или логическими томами) — программные RAID, которые позволяют представить разделы нескольких физических дисков как единое устройство.

При этом два раздела могут просто слиться воедино (Linear RAID), при записи на них может осуществляться расщепление данных (sripping), что приводит к ускорению дисковых операций (RAID-0), на объединённых разделах можно создать различные формы избыточности, обеспечивающей восстановимость данных при отказах дисков — наиболее часто используется полное дублирование (mirror) или избыточность за счет контрольной суммы (RAID-5).

Механизмов создания программных RAID-массивов в Unix-подобных системах много, и останавливаться на них я не буду. При желании материалы о них можно поискать и на этом сайте, например: о RAID во FreeBSD и о RAID в Linux. Есть они также в ряде других статей, косвенно затрагивающих эту тему (поиск по сайту по ключевому слову RAID пока еще не отменен :) ).

Тем более, что ни один из RAID-массивов не решает второй проблемы файловых систем — необходимости расчета потребного для них дискового пространства и, тем более, его перераспределния при необходимости. Этим целям служат другие механизмы — менеджеры логических томов, из которых наиболее известен собственно Logical Volumes Manager, широко используемый в Linux.

Технология LVM предпологает многоуровневую организацию дискового пространства. С одной стороны (как бы «сверху») это группы логических томов, в которые объединяются тома физические, то есть обычные дисковые разделы. С «нижней» же стороны это логические блоки — logical extents, слоего рода логические кванты файловой системы, объединяющие блоки физические (physical extents).

Логический том предстает перед операционной системой как обычное блочное устройство, которое может быть разбито на как бы обычные разделы, логические тома — каждый под свою файловую систему. Казалось бы, чего особенного — ведь объем под каталоги типа /var, /usr или /home все равно придется высчитывать? Да, но механизм LVM предполагает возможность перераспределения дискового пространства между ними — буде таковая необходимость возникнет. И делается это именно посредством добавления или отнятия тех самых квантов-extent’ов. На лету, не только без переразметки дисков, но и без перезапуска системы.

Особенно ярко играет механизм LVM при добавлении в систему нового накопителя. Его нужно просто определить как физический том, добавляемый в существующую группу логических томов — и всё, дело сделано.

Технология LVM обеспечивает и ряд дополнительных возможностей. В частности, она имеет механизм stripping’а, создающий нечто вроде RAID’а нулевого уровня, обеспечивающего повышение быстродействия дисковых операций. С основными ее особенностями можно ознакомиться здесь.

Вроде бы, чего еще желать? Оба поставленных условия — слияние пространства, в том числе и вновь подключаемых дисков, и возможность его перераспределения между существующими файловыми системами, — выполнены.

Да, но тут возникает два осложняющих обстоятельства. Первое затрагивает обычного пользователя. Это — достаточная сложность процедуры установки (подробно описанной по ссылке выше и в ряде других материалов). Будучи обычным пользователем, я ее проделывал неоднократно — и определенно утверждаю, что она требует большой аккуратности (не говоря уже о внимательном чтении документации). Правда, в большинстве современных дистрибутивов Linux’а юзерофильской направленности задействовать LVM можно вполне прозрачно на стадии инсталляции. Но нас ведь интересуют как раз случаи нештатные, не так ли? А тут уж придется поработать и глазам (по man-страницам), и рукам — по клавишам.

Второе же обстоятельство касается уже администраторов, для которых ручное управление LVM труда не составит. Но ведь механизм этот сложноват не только внешне, в использовании, но и внутренне — за счет многоуровневой организации: не будем забывать, что поверх логических томов лежат самые обычные файловые системы, например, ext3 или reiser. И очевидно, что удлинение «цепочки» приводит к снижению надежности — чем больше в ней звеньев, тем вероятней отказ одного из них.

И тут-то и возникает вопрос — а нельзя ли уменьшить количество уровней, сделать систему более «плоской»? Ведь история учит нас, что самыми эффективными системами управления были самые «плоские» — римский легион и административный аппарат Британской Индии.

Правда, история учит нас также тому, что мы обычно ничему у нее не учимся. Но в данном случае, похоже, это не так, и ZFS дает ответ на вопрос предыдущего абзаца.

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

Тут надо сделать маленькое терминологическое отступление. Термин «файловая система» — чуть ли не самый многозначный в компьютерной литературе, больше значений можно насчитать разве что у термина «система». В частности, при разговорах о Unix-подобных системах :) им обозначается и подсистема ядра, отвечающая за управление операциями с файлами, и способ физической организации данных на носителях, и логическая структура файлов и каталогов. Здесь и в последующих заметках термин «файловая система» будет использоваться во втором значении, а для именования логической структуры файлов и каталогов я предпочитаю, для большей однозначности, применять термин «файловая иерархия». Хотя, каюсь, часто сбиваюсь на традиционные именования.

Так вот, к файловой системе в первую голову предъявляются два требования — быстродействия и надежности. Которые, понятное дело, входят в противоречие между собой.

В Unix-подобных системах требование быстродействия удовлетворяется, во-первых, оптимизированным расположением каталогов, метаданных и данных файлов на физических носителя. Но, во-вторых и главных — кэшированием записи.

Думаю, каждого, кто начинал знакомство с Linux’ом, использующим файловую систему ext2fs, поражало, с какой быстротой происходит там копирование данных. Оборотная сторона медали — отказ системы по любой причине влек за собой тяжкие последствия, вплоть до полного ее разрушения. Но и даже когда до полной катастрофы дело не доходило, отказы (например, по питанию) влекли за собой долгую и нудную процедуру проверки целостности файловой системы.

Файловые системы BSD-семейства (например, UFS, используемая во FreeBSD), в которых по умолчанию кэшируются только данные, а метаданные пишутся синхронно, в этом отношении вели себя лучше — но и не столь блистали быстродействием. Да и проверки целостности файловой системы после отказов и там были медленными и печальными.

Были разработаны различные механизмы решения этой проблемы. Так, во FreeBSD был разработан механизм SoftUpdates, который, как это ни парадоксально, способствует не только повышению устойчивости, но и некоторому увеличению быстродействия. Он обеспечивает, с одной стороны, контроль за последовательностью выполнения зависимых обновлений (что способствует целостности состояния файловой системы), с другой — группирует их в единую атомарную операцию синхронного обращения к диску, за счет сокращения числа коих и растет производительность (подробности здесь). Тем не менее, последняя, в сравнении с файловыми системами Linux, всё равно оставляла желать лучшего, особенно с переходом на 64-битную UFS2.

В Linux методы повышения устойчивости файловых систем развивались в другом направлении — так называемого журналирования. Суть его в том, что сведения о файловых операциях записываются в специальный файл журнала до того, как эти операции будут фактически выполнены. Это дает возможность после любого сбоя «откатить» файловую систему до последнего непротиворечивого состояния. Оборотной стороной чего, как обычно, является снижение быстродействия — различное для отдельных файловых систем и видов файловых операций.

Так, если ReiserFS во многих случаях может почти на равных конкурировать с ext2fs (но именно почти), которую можно принять за эталон быстродействия, то журналируемая надстройкак над последней, etx3fs, ведет себя очень по разному при различных режимах журналирования (и, главное, абсолютно непредсказуемым образом). XFS, хорошо проявляющая себя при работе с (очень) большими файлами, пасует перед большими массивами файлов маленьких; а уж удаление последних — это сущий кошмар с точки зрения скорости. О быстродействии JFS говорить без слез трудно — правда, в ее реализации для Linux (говорят, что в родной AIX она показывает себя вполне достойно). Феноменальное быстродействие и надежность обещана в итоговой версии Reiser4 — но боюсь, что нам ее не увидеть никогда; в нынешнем же виде устойчивость ее, мягко говоря, далека от идеала.

Особенности отдельных файловых систем описывались бессчетное число раз. В том числе и на этом сайте содержится столько материалов на эту тему, что я не буду приводить отдельные ссылки, а предлагаю воспользоваться поиском по ключевым словам, таким, как: UFS, UFS2, ext2fs, ext3fs, reiserfs, XFS. Обещаю, улов будет богатым.

Как известно еще с советских атеистических времен, когда Господь создавал человека, он хотел создать его умным, честным и партийным, но больше двух качеств вместе даже он не смог ему дать.

Аналогично и с файловыми системами, точнее, со всем комплексом систем хранения данных, о котором шла речь выше: разработчики хотели бы видеть их быстрыми, надежными и простыми в обращении. Однако до сих пор и у них ничего не получалось. Либо мы имеем плоскую схему «один раздел -> одна файловая система», быструю и простую, но не обеспечивающую надежности. Либо, на другом полюсе, видим многоступенчатую схему из менеджера логических томов, надстраиваемого файловыми системами — которые сами по себе могут быть или быстрыми, или надежными; но в любом случае о простоте обращения говорить не приходится.

Разработчики ZFS поставили себе честолюбивую цель — создать систему хранения данных (а как мы увидим со временем, ZFS — это нечто большее, чем просто файловая система, а именно комплексная система хранения данных), которая отвечала бы всем трем перечисленным критериям. Удалось ли им это? Надеюсь, что по завершении этого цикла заметок читатель сможет составить себе собственное мнение на сей счет. А пока вернемся к истории вопроса.

Разработка ZFS проводилась в компании Sun Microsystems, командой под руководством Джеффа Бонвика (Jeff Bonwick). Результаты этой работы были представлены миру в августе 2004 года — разумеется, в составе OS Solaris. Точнее, ее ядра SunOS — мы ведь часто забываем, что Solaris — это имя всего программного комплекса, включая пользовательское окружение, а ядро системы компании Sun как носило имя SunOS испокон веков, так и носит его по сей день, именуясь SunOS 5 (хотя об этом не любят говорить вслух :) ). Так что пользователям свободных систем поначалу от ее существования было ни холодно, ни жарко.

Кстати, первоначально название ZFS рассматривалось как аббревиатура Zettabyte File System, но ныне это просто условное именование. Его можно интерпретировать как то, что символ Z ставит точку в развитии файловых систем. И в некоторых отношениях, как мы увидим в последующем, это недалеко от истины.

Период камерного существования ZFS продолжался недолго — уже в ноябре 2005 года ее поддержка была интегрирована в OpenSolaris — открытый и свободный клон SunOS. Который, кстати, правильнее было бы действительно называть OpenSunOS, ибо ряд компонентов полного комплекса Solaris не являются собственностью компании Sun и, соответственно, открыты быть не могли.

Исходники ZFS распространяются, как и собственно ядро SunOS, под лицензией CDDL (Common Development and Distribution License). Эта лицензия, базирующаяся на Mozilla Public License (MPL), не влияет на общую лицензию проекта, в состав который включены CDDL-компоненты.

Впрочем, к этому вопросу мы еще вернемся. А пока замечу только, что открытие исходников Solaris породило не очень интенсивное, но все же заметное клонмейкерство. На базе ее разрабатываются такие «дистрибутивы», как BeleniX, Indiana, SchilliX. Правда, о числе их пользователей можно только гадать.

По причинам, на которых я остановлюсь под занавес, в рамках нашей темы наибольший интерес представляет Nexenta OS. Это весьма своеобразный гибрид из ядра SunOS (и, разумеется, ее системного окружения), пользовательских утилит GNU и инфраструктуры, заимствованной у Debian — deb-пакетов, объединенных в репозитории. Кое-какие подробности о ней можно прочитать РубрикиFreeBSD, Свалка истории