Надежность дисковой системы NT. Что такое журналируемые файловые системы

Основная цель, которая преследуется при создании журналируемых файло-вых систем, состоит в том, чтобы обеспечить как можно большую вероят-ность быстрого восстановления системы после сбоев (например, после по-тери питания). Дело в том, что если происходит сбой, то часть информации о расположении файлов теряется, поскольку система не успевает записать все изменения из буфера на диск. После сбоя утилита, например, fsck должна прове-рить все диски, которые не были корректно демонтированы, с целью вос-становления потерянной информации. При современных объемах жестких дисков, на проверку двух-трех таких дис-ков может уйти слишком много времени. Кроме того, нет гарантии, что все данные удастся восстановить.

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

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

Пример1. Файловая система Ext3

По большому счету, файловая система Ext3 не была новой файловой системой. Это похоже на ситуацию с файловой системой FAT 16/FAT 32 — они совместимы, но проблема решена экстенсивным путем. Было необхо-димо срочно создать журналируемую файловую систему. Если начинать с нуля — долго и накладно, тогда сделали для Ext2 несколько десятков специ-альных функций и назвали все это Ext3 — получился непонятный гибрид.

Файловая система ext3 имеет несколько опций, которые позволяют выбрать, сколько информации нужно журналировать. В системе Red Hat Linux, чтобы прочитать и восстановить данные из обычного журнала, требуется около секунды. Время, необходимое для восстановления журнальной файловой системы после неправильного выключения компьютера, зависит не от размера файловой системы, а от того, сколько данных содержится в журнале.

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

При выборе опций журналирования можно отключить проверку целостности данных при пересылке, чтобы увеличить скорость выполнения операций в файловой системе; из-за конструкции файловой системы нужно выбирать что-то одно: либо обеспечение целостности, либо скорость. Можно повысить скорость обработки данных, установив для них режим Writeback. Но при этом данные могут повредиться, если во время операции над ними произойдет аварийное выключение компьютера. Или же можно пожертвовать скоростью выполнения операций, но обеспечить целостность данных.

В файловой системе ext3 доступны 3 режима работы с данными:

  • Writeback - позволяет старым данным оставаться в системе, при этом операции над этими данными, как правило, выполняются быстрее. Этот режим не предусматривает планирование каких-либо операций над данными.
  • Ordered - хранит данные в согласованном состоянии, однако скорость выполнения операций над данными падает (этот режим установлен по умолчанию).
  • Journal - требует дополнительного пространства на диске для выполнения журналирования. При этом может упасть производительность, поскольку данные записываются дважды.

Для большинства пользователей наилучшим режимом будет Ordered , который выбран по умолчанию. Режим выбирается с помощью соответствующей опции монтирования в файле /etc/fstab.

Пример2. Файловая система ReiserFS

Кроме проблемы быстрого восстановления после сбоев, в файловой системе Ext2 имеется еще несколько нерешенных проблем. Из самых основных — нерациональное использование дискового пространства, ограничение на размер файла, неоптимальный поиск.

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

В системе ReiserFS применяются так называемые "сбалансированные дере-вья" или "B+Trees", время поиска в которых пропорционально не количест-ву объектов, а логарифму этого числа. В сбалансированном дереве все ветви имеют одинаковую длину. ReiserFS использует сбалансированные деревья для хранения всех объектов файловой системы: файлов в каталогах, данных о свободных блоках и т.д. Это позволяет существенно повысить производи-тельность обращения к дискам.

Кроме того, система ReiserFS является журналируемой, т.е. в ней решена проблема быстрого восстановления после сбоев. Решена в ReiserFS и про-блема с ограничением на размер файла.

Изначально стандартной файловой системой для Linux была Ext2fs. Ext2 основана на структуре i-node. I-node содержит информацию о файле и указатели на блоки данных, в которых расположен файл. Для повышения быстродействия операций ввода/вывода данные временно располагаются в оперативной памяти. Проблема возникает, если сбой происходит до того, как данные из кэша перепишутся на диск. Это вызывает несоответствие в файловой системе. Например, возникает ссылка на файл, еще не созданный на диске, или файлы были уже удалены, но их i-nodes и блоки данных остались на диске. Fsck (File system check – проверка файловой системы) – стандартная программа для устранения несоответствий. Единственный способ это сделать – просканировать весь диск, и проверить все зависимости между i-nodes, блоками данных и содержанием директорий. С увеличением объемов дисков эта процедура стала занимать огромное количество времени – серьезная проблема для серверов, которые должны работать постоянно.

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

Журналируемая файловая система – это устойчивая к сбоям файловая система, в которой целостность данных гарантирована, потому что обновления в meta-данных файлов записываются в log на диске перед любыми изменениями в структуре файловой системы. В случае сбоя журналируемая файловая система гарантирует восстановление всех потерянных данных. Самый распространенный подход – это метод журналирования или логгирования meta-данных файлов. Его суть в том, что информация о любом изменении записывается в зарезервированную область файловой системы, и только после этого совершается само изменение.

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

Linux имеет три основные журналируемые FS – это ReiserFS от Namesys, XFS от SGI, и Ext3, разработанная Stephen Tweedie, участвовавшим в создании Ext2.

Самый простой инструмент для улучшенного по сравнению с традиционными Unix-системами быстродействия – это избежание использования связанных списков или bitmaps, которые содержат в себе проблему масштабируемости и неприменимы для новых дисков с огромной вместимостью. Все новые системы используют Balanced Trees (B-Trees), или их вариацию (B+Trees).

Дерево состоит из внутренних и листовых узлов. Каждый узел (node) – это дисковый блок. Каждому объекту (файлу, каталогу) назначается уникальный ключ, аналогичный номеру inode в других файловых системах. Внутренние узлы, главным образом, состоят из ключей и указателей на узлы-потомки. Узел, который начинает дерево, известен как корень; узлы, которые сидят на конце ветви дерева иногда называются листьями.

Время поиска в B+Trees пропорционально не количеству объектов (файлов в каталоге или числа блоков на диске), а логарифму этого числа. В сбалансированном дереве все ветви (пути от корня до «листа») имеют одинаковую (или примерно одинаковую) длину.

ReiserFS базируется на B+Tree в организации объектов файловой системы. ReiserFS предоставляет только журналирование meta-данных. В случае незапланированной перезагрузки данные в блоках, используемых во время сбоя, могут быть повреждены, так что ReiserFS не гарантирует того, что после сбоя данные останутся неповрежденными.

ReiserFS также имеет ряд особенностей, нацеленных специально для улучшения работы с маленькими файлами. Одна из специальных возможностей ReiserFS – это Tail Packing. Tail – это файл, размер которого меньше, чем логический блок, или какие-то части файлов, занимающие меньше, чем один блок. Для сохранения свободного места ReiserFS использует сжатие tail-файлов, и это позволяет примерно на 5 % увеличить свободное место по сравнению с Ext2. Для увеличения скорости, ReiserFS способен хранить содержимое файлов непосредственно внутри b*tree, а не в виде указателя на дисковый блок.

XFS была создана в начале 90-х (1992–1993) фирмой Silicon Grapgics (сейчас SGI) для мультимедийных компьютеров с ОС Irix. Файловая система была ориентирована на очень большие файлы и файловые системы. 1 мая 2001 года SGI выпустила первый релиз XFS для Linux.

Для увеличения масштабируемости файловой системы XFS обширно использует B+Trees. XFS допускает хранение журнала на другом блочном устройстве.

XFS имеет такую возможность, как delayed allocation (Отложенное размещение) – вместо того, что бы выделять блоки файлу в момент его записи в кэш, XFS просто резервирует блоки в файловой системе, размещая данные в специальных виртуальных зонах (virtual extents). Когда весь файл содержится в памяти, то он обычно может быть размещен в одном куске непрерывного дискового пространства. Тем самым предотвращается фрагментация файлов.

Максимальный размер файла – 9 млн. Тбайт

В ReiserFS неожиданная перезагрузка может иметь результатом попадание в изменяемый файл фрагмента из когда-то удаленного файла. Помимо очевидной потери данных, гипотетически это может иметь более серьезные последствия. В XFS имеется гарантия, что любые «недозаписанные» блоки заполнены нулями. Так как блоки с нулевыми байтами в системных файлах игнорируются, устраняется лазейка в безопасности.

Ext3 – надстройка над Ext2. С одной стороны, она позволяет вести лог операций для более быстрого восстановления. Но эта файловая система унаследовала некоторые ограничения от Ext2 (например, она базируется на блоках и использует полный перебор при поиске файлов и директорий), и поэтому ее нельзя назвать чистой журналируемой файловой системой.

Журнал располагаться в любой другой файловой системе. Возможно иметь несколько файловых систем Ext3 с совместным журналом.

Типы журналирования поддерживаемые Ext3, которые могут быть активированы из файла /etc/fstab:

  • data=journal (full data journaling mode) – все новые данные сначала пишутся в журнал и только после этого переносятся на свое постоянное место. В случае аварийного отказа журнал можно повторно перечитать, приведя данные и метаданные в непротиворечивое состояние. Самый медленный, но самый надежный.
  • data=ordered – записываются изменения только метаданных файловой системы, но логически metadata и data блоки группируются в единый модуль, называемый transaction. Перед записью новых метаданных на диск, связанные data блоки записываются первыми. Этот режим установлен по умолчанию. При добавлении данных в конец файла режим data=ordered гарантированно обеспечивает целостность (как при full data journaling mode). Однако, если данные в файл пишутся поверх существующих, то есть вероятность перемешивания «оригинальных» блоков с модифицированными. Это результат того, что data=ordered не отслеживает записи, при которых новый блок ложится поверх существующего и не вызывает модификации метаданных.
  • data=writeback (metadata only) – записываются только изменения метаданных файловой системы. Самый быстрый метод журналирования. Аналогичен используемому в XFS и ReiserFS.

Файловая система NTFS начала свое существование вместе с Windows NT 3.5 в 1993 году. Она умеет управлять дисками размером до нескольких сотен терабайт.

Каждый файл на томе NTFS представлен записью в специальном файле, называемом главной файловой таблицей (MFT – master file table). Первая запись этой таблицы описывает непосредственно главную файловую таблицу;

За ней следует зеркальная запись (mirror record) MFT. Если первая запись MFT разрушена, то NTFS читает вторую запись для отыскания зеркального файла MFT.

Третья запись MFT – файл регистрации (log file); содержит список шагов транзакции, используемых Log File System для восстановления файлов в случае сбоя. Семнадцатая и последующие записи главной файловой таблицы используются собственно файлами и каталогами.

Небольшие файлы и каталоги могут полностью содержаться внутри записи главной файловой таблицы. Большие каталоги организованы в B-tree, имея записи с указателями на внешние кластеры, содержащие элементы каталога, которые не могли быть записаны внутри структуры MFT.

Журналирование NTFS

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

Отложенная запись и контрольные точки журналирования

Известно, что любая современная система для ускорения файловых операций вынуждена использовать кэширование, в том числе - кэширование операций записи. Так называемая отложенная запись - принцип кэширования, при котором данные, предназначенные для записи на диск, некоторое время сохраняются в КЭШе и лишь в свободное от других занятий время сохраняются физически. Отложенная запись существенно повышает эффективность дисковых операций, так как такое кэширование группирует множество операций в одну - это особенно эффективно, если запись производится в компактные участки диска. Еще один плюс отложенной записи - не мешать более нужным операциям чтения, и осуществлять запись только тогда, когда система свободна и ей не требуется доступ к диску для других нужд. Как согласовать отложенную запись с журналированием? Это довольно сложный вопрос, так как откладывание записи делает возможным потерю тех данных, которые находились в очереди на физическую запись и не успели записаться на диск до сбоя. Самое неприятное здесь даже не потеря данных, а то, что происходит рассогласование времени записи: какие-то служебные области могут быть обновлены, а какие-то смежные по смыслу - еще нет, так как их обновление могло отложится еще на пару секунд и не состоятся из-за сбоя.

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

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

При обычной работе файловой системы все изменения обычно сразу производятся с диском (вернее с кэшем диска в ОС, но это в данном контексте не важно).


Многие операции требует одновременного изменения сразу нескольких структур файловой системы (метаданных . Простой пример: при создании hardlink"а нужно одновременно увеличить количество ссылок на inode и изменить содержимое каталога, в который делается ссылка. Нельзя сделать лишь одну из этих операций — содержимое файловой системы будет некорректным.


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


Так как после перезагрузки мы не знаем какие операции производились, что было незакончено, а знаем только о том, что диск не был корректно размонтирован (при этом сбрасывается так называемый dirty flag), то нам необходимо проанализировать файловую систему на всём диске, и, таким образом, выявить все ошибки в файловой системе и их исправить. Естественно далеко не всегда это возможно выполнить автоматически (неестественный интеллект, увы, способностям к ясновидению пока обучить никому не удалось), посему та же fsck.ext2 после нештатной перезагрузки может потребовать и ручного вмешательства.


Те, кто запускал fsck на разделе в 100-200 G (что ныне далеко не редкость) прекрасно понимают, что удовольствия в этом мало. Администраторы же многотерабайтовых массивов, за лишнюю минуту простоя коих им могут «случайно» голову оторвать при слове “fsck” хватаются за валерьянку или просят не ругаться такими словами в их присутствии.


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


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


Цена этого удовольствия: у нас образуется небольшая (обычно измеряемая десятками мегабайт) область диска, на которую приходится максимальная нагрузка, то есть максимальное производительность, измеряемая в количестве i/o операций в секунду, падает. Ну и, естественн, расходуется немного дискового пространства, что в эпоху цен на диски < 1$/гигабайт никого не волнует.

Журналирование данных

Как вы обратили внимание, в журнал обычно пишутся операции с метаданными. Однако можно то же самое делать и с данными.


Насколько мне известно под Linux журналирование данных умеет выполнять лишь ext3 с параметром data=journal.


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


Это средство тоже не гарантирует сохранность данных, однако из моего личного опыта использование ext3 с data=journal является самой надёжной файловой системой.

Производительность

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


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


Во-вторых можно использовать специальные карты энергонезависимой памяти (например UMEM, коих я, увы, на территории России в продаже не видел), которые ещё и заметно быстрее обычных дисков (но имеют небольшой размер памяти).


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

Хитрости

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

  • отложеное создание файла (в момент создания файла не создавать сразу запись в каталоге, а некоторое время держать её только в журнале, возможно файл временный и будет сразу удалён);
  • отложеное размещение файла (не выделять физически место даже под первый блок файла до тех пор, пока не понадобится записать хотя бы один блок), вполне возможно, что пользователь сначала изменит размер файла, а уж потом начнёт записывать данные. Как результат уменьшается фрагментация (если программы пользуются этим трюком);

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

Недостатки

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


Да, не матюгнётся. И будет абсолютно корректной с точки зрения какого-нибудь fsck файловой системой. Только вот от данных при этом всё равно могут остаться одни ошмётки.


Скажем reiserfs в подобных ситуациях вполне может оставлять в модифицируемых файлах мусор (произвольные данные которые были в выделеном под файл блоке). Что, по сути, означает вполне вероятную случайную утечку информации.


XFS поступает более корректно — она такие блоки прописывает нулями. Что часто шокирует пользователей. Особенно фанатов reiserfs, которая не станет прописывать нулями.


В результате reiserfs скорее сохранит модификации, а XFS всеми силами избежит мусора в файлах и утечки данных — просто чуть разные стратегии. Результат один — данные могут быть утеряны, и вы даже об этом не узнаете. Пока не столкнётесь с файлом, который уже год никто не трогал (в архиве лежал), и который вдруг оказался забитым мусором или нулями.


ext3 с включеным журналированием данных такими особенностями не страдает. Однако заметно проигрывает в производительности.


По-хорошему всех этих проблем можно (и нужно) избежать просто покупкой UPS, а журналирование использовать лучше как дополнительный уровень надёжности и средство увеличения производительности.

Итог

Журналируемая файловая система всего лишь немного облегчает администрирование, однако не является волшебным средством от потери данных при нештатных перезагрузках. Поэтому если вы не пользуетесь UPS и не делаете Backup, то ваши данные рано или поздно накроются медным тазом, чего я вам искренне НЕ желаю. А если захотеть, то можно использовать журналируемые файловые системы как средство увеличения производительности.


Кто купил UPS И backup делает Того данные всегда целы


(C) Денис Смирнов 5 Nov 2004
Размещение этого документа на других Internet-ресурсах, а также в печатных изданиях не допускается.