Журналируемая файловая система — это файловая система , которая отслеживает изменения, еще не зафиксированные в основной части файловой системы , записывая цель таких изменений в структуру данных, известную как « журнал », которая обычно представляет собой циклический журнал . В случае сбоя системы или отключения питания такие файловые системы могут быть восстановлены быстрее с меньшей вероятностью повреждения . [ 1] [2]
В зависимости от фактической реализации, журналируемая файловая система может отслеживать только сохраненные метаданные , что приводит к повышению производительности за счет увеличения вероятности повреждения данных. В качестве альтернативы, журналируемая файловая система может отслеживать как сохраненные данные, так и связанные с ними метаданные, в то время как некоторые реализации допускают выборочное поведение в этом отношении. [3]
В 1990 году IBM представила JFS в AIX 3.1 как одну из первых коммерческих файловых систем UNIX, которая реализовала журналирование. [4] В следующем году эта идея была популяризирована в широко цитируемой статье о файловых системах с журнальной структурой. [5] Впоследствии она была реализована в файловой системе NTFS от Microsoft Windows NT в 1993 году, в файловой системе HFS Plus от Apple в 1998 году и в файловой системе ext3 от Linux в 2001 году. [6]
Обновление файловых систем для отражения изменений в файлах и каталогах обычно требует множества отдельных операций записи. Это делает возможным прерывание (например, сбой питания или сбой системы ) между записями, которое может оставить структуры данных в недопустимом промежуточном состоянии. [1]
Например, удаление файла в файловой системе Unix включает три шага: [7]
Если сбой происходит после шага 1 и до шага 2, будет потерянный inode и, следовательно, утечка памяти ; если сбой происходит между шагами 2 и 3, то блоки, ранее используемые файлом, не могут быть использованы для новых файлов, что эффективно уменьшает емкость хранилища файловой системы. Переупорядочивание шагов также не помогает. Если шаг 3 предшествовал шагу 1, сбой между ними может позволить повторно использовать блоки файла для нового файла, то есть частично удаленный файл будет содержать часть содержимого другого файла, и изменения в любом из файлов будут отображаться в обоих. С другой стороны, если шаг 2 предшествовал шагу 1, сбой между ними приведет к тому, что файл станет недоступным, несмотря на то, что он, по-видимому, существует.
Обнаружение и восстановление после таких несоответствий обычно требует полного обхода структур данных, например, с помощью такого инструмента, как fsck (средство проверки файловой системы). [2] Обычно это должно быть сделано до того, как файловая система будет смонтирована для доступа на чтение и запись. Если файловая система большая и пропускная способность ввода-вывода относительно мала, это может занять много времени и привести к более длительным простоям, если это заблокирует остальную часть системы от возвращения в строй.
Чтобы предотвратить это, журналируемая файловая система выделяет специальную область — журнал — в которой она записывает изменения, которые она сделает заранее. После сбоя восстановление просто включает чтение журнала из файловой системы и воспроизведение изменений из этого журнала до тех пор, пока файловая система снова не станет согласованной. Таким образом, изменения называются атомарными (неделимыми), поскольку они либо успешно выполняются (изначально успешно или полностью воспроизводятся во время восстановления), либо не воспроизводятся вообще (пропускаются, поскольку они еще не были полностью записаны в журнал до того, как произошел сбой).
Некоторые файловые системы позволяют журналу увеличиваться, уменьшаться и перераспределяться как обычный файл, в то время как другие помещают журнал в непрерывную область или скрытый файл, который гарантированно не будет перемещаться или менять размер, пока файловая система смонтирована. Некоторые файловые системы также могут разрешать внешние журналы на отдельном устройстве, например, твердотельном диске или энергонезависимой оперативной памяти с резервным питанием от батареи. Изменения в журнале могут сами журналироваться для дополнительной избыточности, или журнал может быть распределен по нескольким физическим томам для защиты от сбоя устройства.
Внутренний формат журнала должен защищать от сбоев во время записи в сам журнал. Многие реализации журнала (например, слой JBD2 в ext4 ) ограничивают каждое зарегистрированное изменение контрольной суммой, понимая, что сбой оставит частично записанное изменение с отсутствующей (или несовпадающей) контрольной суммой, которую можно просто проигнорировать при повторном воспроизведении журнала при следующем перемонтировании.
Физический журнал регистрирует предварительную копию каждого блока, который позже будет записан в основную файловую систему. Если при записи в основную файловую систему происходит сбой, запись можно просто воспроизвести до завершения при следующем монтировании файловой системы. Если при записи в журнал происходит сбой, частичная запись будет иметь отсутствующую или несовпадающую контрольную сумму и может быть проигнорирована при следующем монтировании.
Физические журналы приводят к значительному снижению производительности, поскольку каждый измененный блок должен быть дважды зафиксирован в хранилище, но могут быть приемлемы, когда требуется абсолютная защита от сбоев. [8]
Логический журнал хранит только изменения метаданных файла в журнале и жертвует отказоустойчивостью ради существенно более высокой производительности записи. [9] Файловая система с логическим журналом по-прежнему быстро восстанавливается после сбоя, но может допустить, чтобы нежурналируемые данные файла и журналируемые метаданные перестали синхронизироваться друг с другом, что приведет к повреждению данных.
Например, добавление в файл может включать три отдельные записи:
В журнале, содержащем только метаданные, шаг 3 не будет зарегистрирован. Если шаг 3 не был выполнен, но шаги 1 и 2 были воспроизведены во время восстановления, файл будет дополнен мусором.
Кэш записи в большинстве операционных систем сортирует свои записи (используя алгоритм лифта или какую-либо подобную схему) для максимизации пропускной способности. Чтобы избежать опасности записи вне очереди с журналом, содержащим только метаданные, записи для файловых данных должны быть отсортированы так, чтобы они были зафиксированы в хранилище до связанных с ними метаданных. Это может быть сложно реализовать, поскольку это требует координации в ядре операционной системы между драйвером файловой системы и кэшем записи. Опасность записи вне очереди также может возникнуть, если устройство не может немедленно записывать блоки в свое базовое хранилище, то есть оно не может сбросить свой кэш записи на диск из-за включенной отложенной записи.
Чтобы усложнить ситуацию, многие устройства массовой памяти имеют собственные кэши записи, в которых они могут агрессивно переупорядочивать записи для повышения производительности. (Это особенно распространено на магнитных жестких дисках, которые имеют большие задержки поиска, которые можно минимизировать с помощью сортировки лифтом.) Некоторые журналируемые файловые системы консервативно предполагают, что такое переупорядочение записи всегда имеет место, и жертвуют производительностью ради корректности, заставляя устройство очищать свой кэш в определенных точках журнала (называемых барьерами в ext3 и ext4 ). [10]
Некоторые реализации UFS избегают журналирования и вместо этого реализуют мягкие обновления : они упорядочивают свои записи таким образом, что файловая система на диске никогда не бывает несогласованной, или что единственной несогласованностью, которая может возникнуть в случае сбоя, является утечка хранилища. Чтобы восстановиться после этих утечек, карта свободного пространства согласовывается с полным обходом файловой системы при следующем монтировании. Эта сборка мусора обычно выполняется в фоновом режиме. [11]
В файловых системах с журнальной структурой штраф за двойную запись не применяется, поскольку сам журнал является файловой системой: он занимает все устройство хранения и структурирован таким образом, что его можно просматривать так же, как и обычную файловую систему.
Полные файловые системы копирования при записи (такие как ZFS и Btrfs ) избегают изменений на месте в данных файла, записывая данные в новые выделенные блоки, за которыми следуют обновленные метаданные, которые будут указывать на новые данные и отрекаться от старых, за которыми следуют метаданные, указывающие на них, и так далее до суперблока или корня иерархии файловой системы. Это имеет те же свойства сохранения корректности, что и журнал, без накладных расходов на двойную запись.