ZFS: Переосмысление традиционной архитектуры хранения данных (ч.2)
Целостность данных в ZFS
Одной из важнейших задач любой файловой системы является обеспечение целостности данных — их защиты от повреждений, вызванных аппаратными или программными сбоями. Аппаратные сбои охватывают широкий спектр проблем, от физического выхода из строя компонентов до некорректной работы оборудования. Программные сбои могут быть вызваны ошибками в ПО, включая вредоносный код. Повреждение данных может проявляться по-разному: замедление работы системы, сбои программ, проблемы с доступом к файлам и, в худшем случае, необратимая потеря информации. С ростом емкости и скорости накопителей возрастает и вероятность возникновения незаметных повреждений данных (так называемое "битовое гниение" или bit rot), что делает надежные механизмы обеспечения целостности все более критичными.
ZFS изначально разрабатывалась с фокусом на преодоление известных недостатков традиционных RAID-массивов, в частности, проблемы "дыры записи" (write hole) в RAID-5/6. "Дыра записи" возникает, когда сбой системы (например, потеря питания) происходит в момент, когда новые данные уже записаны на диск, а соответствующий блок чётности ещё не обновлен. Это приводит к рассинхронизации данных и чётности, что может повлечь потерю данных при последующем восстановлении.
Механизмы защиты данных применяемые в ZFS:
-
Использование контрольных сумм: Фундаментальным аспектом целостности данных в ZFS является использование контрольных сумм (таких как Fletcher или SHA-256), которые вычисляются для каждого блока данных и метаданных во всем дереве файловой системы. Эти контрольные суммы хранятся в указателе на блок, а не вместе с самим блоком.
Хранение контрольной суммы в указателе на блок, а не рядом с самими данными, позволяет ZFS обнаруживать не только битовые ошибки внутри блока, но и ситуации, когда операция чтения извлекает данные из непреднамеренного места (ошибочное чтение).
-
Транзакционная природа и Copy-on-Write (COW): ZFS использует механизм copy-on-write, при котором изменения данных записываются в новые блоки на хранилище. Указатели метаданных обновляются на эти новые блоки только после успешного завершения записи и вычисления контрольной суммы. Такой транзакционный подход гарантирует, что файловая система остается согласованной даже в случае неожиданных прерываний, таких как потеря питания. Сочетание copy-on-write и контрольного суммирования в ZFS обеспечивает надежную защиту от повреждения данных во время системных сбоев, поскольку незавершённые записи никогда не фиксируются, а целостность данных проверяется до завершения обновления.
-
Структура дерева Меркла: ZFS организует свои данные с использованием дерева Меркла. В этой структуре каждый узел содержит контрольную сумму всех своих дочерних узлов, простирающуюся до корня. Такое иерархическое контрольное суммирование позволяет ZFS проверять целостность всей структуры файловой системы. Если один блок поврежден, контрольная сумма его родительского узла перестанет совпадать, и это несоответствие распространится вверх по дереву, позволяя ZFS точно определить местоположение поврежденных данных.
-
Избыточность на уровне vdev: Хотя перечисленные механизмы (контрольные суммы, COW, дерево Меркла) обеспечивают обнаружение и предотвращение логических повреждений, они не могут защитить от полного физического отказа диска. Для решения данной проблемы и обеспечения целостности данных ZFS предлагает использовать методы резервирования данных на разных физических дисках (зеркалирование, RAIDZ, dRAID) в зависимости от критичности данных и желаемого уровня отказоустойчивости. Виды резервирования данных, а также различные нюансы при их использования будут рассмотрены далее.
Организация дисков в ZFS: от простого объединения до сложных RAID-схем
Резервирование данных — это критически важный процесс для обеспечения их сохранности и доступности. Жесткие диски и другие носители информации имеют ограниченный срок службы и могут выйти из строя в любой момент. Резервирование позволяет сохранить данные в случае поломки одного или нескольких носителей. Для этой цели часто используется технология RAID (Redundant Array of Independent Disks), которая объединяет несколько физических дисковых устройств в один логический модуль для повышения отказоустойчивости и/или производительности. Важно понимать, что RAID защищает от отказа дисков, но не от случайного удаления файлов пользователем, повреждения данных вирусами или физического уничтожения всего массива (например, при пожаре).
ZFS предлагает различные виды объединения дисков в один логический, каждый из которых предлагает свой баланс между отказоустойчивостью, скоростью чтения и записи, полезным объёмом данных:
-
Stripe — диски логически соединяются в один без избыточности, скорость записи и чтения всех дисков суммируется.
-
Mirror — зеркалирование данных на все диски, схема особенно полезна в случае хранения особо важных данных.
-
RAIDZ — Собственная реализация ZFS, схожая с RAID-5/6, но лишенная их недостатков, таких как "дыра записи", благодаря механизму COW. Основная концепция заключается в чередовании данных и информации о чётности (parity) по всем дискам в группе. Существует 3 варианта RAIDZ, которые отличаются показателем избыточности.
-
dRAID — это новая схема распределённого RAID, представленная в OpenZFS 2.1. При использовании данной схемы значительно повышается скорость ресильверинга (resilvering), то есть процесса восстановления данных на замененный или резервный диск после сбоя. Это достигается за счет интеграции распределенных горячих резервов (distributed hot spares) непосредственно в vdev и параллельного восстановления данных всеми оставшимися дисками. В отличие от RAIDZ, dRAID использует фиксированную ширину страйпа, что может приводить к некоторому неэффективному использованию пространства при хранении большого количества мелких файлов (из-за заполнения нулями неполных страйпов), но это является осознанным компромиссом ради ускорения восстановления. Как и RAIDZ, dRAID имеет три уровня избыточности: dRAID1, dRAID2 и dRAID3.
Сравнение dRAID с RAIDZ
Хотя и RAIDZ, и dRAID служат цели обеспечения избыточности хранения данных в ZFS, между ними существуют ключевые различия, влияющие на производительность, эффективность использования пространства и, что особенно важно, на процесс восстановления после сбоя диска.
-
Распределение чётности и горячие резервы:
-
В RAIDZ информация о чётности распределяется по всем дискам в пределах vdev. Горячие резервы (hot spares), если они настроены, являются отдельными, выделенными дисками в пуле, которые остаются бездействующими до момента сбоя, потребляя минимальное количество ресурсов (хотя физически они включены). Когда диск в RAIDZ vdev выходит из строя, ZFS начинает процесс ресильверинга, восстанавливая данные на этот выделенный резервный диск.
-
В dRAID концепция горячих резервов иная: резервное пространство интегрировано и распределено по всем дискам внутри vdev с самого начала. Нет отдельных простаивающих дисков. При сбое диска все оставшиеся диски в dRAID vdev участвуют в восстановлении данных на это распределенное резервное пространство.
-
Процесс восстановления (ресильверинг):
-
RAIDZ использует так называемое "лечащее восстановление" (healing resilver). ZFS сканирует метаданные, чтобы найти все блоки, которые необходимо восстановить, и записывает их на новый (резервный) диск. При этом проверяется контрольная сумма каждого восстанавливаемого блока. Этот процесс может быть достаточно медленным на больших vdev с большим количеством мелких файлов, так как требует множества случайных операций чтения.
-
dRAID использует "последовательное восстановление" (sequential resilver). Восстановление происходит путем последовательного чтения данных с оставшихся дисков и записи восстановленных данных в распределенное резервное пространство, руководствуясь заранее вычисленными картами перестановок. Это позволяет выполнять более крупные операции ввода-вывода, что значительно быстрее, особенно на HDD. Однако контрольные суммы во время самого этого быстрого восстановления не проверяются; для проверки целостности восстановленных данных обычно запускается отдельная операция очистки (scrub) после завершения ресильверинга.
Ключевые аспекты работы горячих резервов в dRAID:
-
Распределенные резервы: Резервное пространство интегрировано в структуру VDEV и распределено по всем дискам. Нет отдельных физических дисков, назначенных исключительно под горячий резерв в привычном понимании.
-
Непрерывное участие всех дисков: Все диски в VDEV dRAID активно участвуют как в операциях чтения/записи данных, так и в предоставлении резервного пространства.
-
Параллельный и быстрый ресильверинг: Когда диск в dRAID выходит из строя, восстановление данных на распределенное резервное пространство происходит параллельно с оставшихся дисков VDEV. Это значительно ускоряет процесс ресильверинга по сравнению с RAIDZ, поскольку нагрузка на запись распределяется между всеми дисками.
-
Уменьшение окна уязвимости: Благодаря быстрому ресильверингу время, в течение которого пул находится в деградированном состоянии и уязвим к дополнительным сбоям, значительно сокращается.
-
Автоматическое перебалансирование: После физической замены сбойного диска ZFS выполняет операцию перебалансирования, чтобы вернуть распределенное резервное пространство в его обычное состояние и интегрировать новый диск в VDEV.
Конфигурация dRAID с распределенными резервами задается при создании пула с использованием синтаксиса dRAID, указывающего количество дисков данных, четности и распределенных резервов.
Таблица 1: Сравнение dRAID и RAIDZ
Функция |
dRAID |
RAIDZ |
Распределение чётности |
Внутри групп избыточности, распределено по всем дочерним дискам |
По всем дискам в vdev |
Горячие резервы |
Интегрированы и распределены как зарезервированное пространство на всех дисках |
Выделенные, бездействующие диски |
Восстановление |
Последовательное, управляемое картами пространства, быстрее, требует последующей очистки |
Лечащее, сканирует дерево блоков, медленнее, проверяет контрольные суммы во время восстановления |
Ширина полосы |
Фиксированная |
Переменная |
Эффективность |
Потенциально ниже для небольших файлов из-за заполнения |
Обычно выше, более эффективно с небольшими файлами |
Добавление резервов |
Только во время создания vdev |
Можно добавить в пул после создания vdev |
Масштабируемость |
Оптимизировано для больших массивов (20+) |
Хорошо работает для небольших массивов |
Проверка контрольных сумм |
После восстановления (через очистку) |
Во время восстановления |
Таблица 2: Сравнение всех типов vdev
Характеристика |
Stripe |
Mirror |
RAIDZ(К) |
dRAID(K) |
Аналог (если есть) |
RAID-0 |
RAID-1 |
RAID-5/6 |
нет |
Минимальное количество дисков |
1 |
2 |
2 + K |
2 + K |
Отказоустойчивость |
0 |
N-1 |
K |
K |
Скорость записи |
Максимально возможная. Скорость суммируется |
Равна скорости самого медленного диска |
Приближается к скорости записи N-K самого медленного диска в массиве |
Сопоставима с RAIDZ; улучшенная скорость восстановление дисков |
Скорость чтения |
Максимально возможная. Скорость суммируется |
Равна скорости самого медленного диска |
Сопоставима для всех уровней RAIDZ |
Сопоставима с RAIDZ |
Полезное пространство |
N (почти всё пространство дисков) |
1 (полезным является пространство одного диска) |
N-K |
N-K, меньше чем в RAIDZ, за счёт фиксированной ширины полосы |
Сложность восстановления |
Максимальная |
Может потребоваться только в случае выхода из строя всех дисков |
Легко; Долго |
Легко; Быстро |
Ключевые недостатки |
Отсутствие избыточности |
Низкая эффективность использования пространства |
Полезное пространство; Скорость чтения и записи |
Меньшая полезная емкость по сравнению с RAIDZ |
Примечание: N - общее количество дисков в vdev, K - количество дисков чётности (1 для RAIDZ1/dRAID1, 2 для RAIDZ2/dRAID2, 3 для RAIDZ3/dRAID3).
Разница в скорости записи в режимах Stripe, RAIDZ и dRAID
В RAIDZ и dRAID скорость записи значительно ниже, чем у stripe. Это связано с необходимостью вычисления и записи информации о чётности. Для каждой операции записи ZFS может потребоваться:
-
Чтение существующих данных (иногда).
-
Чтение существующих данных чётности (иногда).
-
Вычисление новой чётности.
-
Запись новых данных.
-
Запись новой чётности.
Этот процесс, известный как "write penalty", делает запись в RAIDZ и dRAID более ресурсоемкой и медленной, особенно для небольших случайных записей. Чем выше уровень избыточности, тем больше информации о чётности необходимо записать, что еще больше снижает скорость записи.
В общем случае, можно ожидать снижения скорости записи в RAIDZ и dRAID как минимум на величину, связанную с необходимостью записи дополнительной информации о чётности.
Теоретически, скорость последовательной записи для RAIDZ и dRAID может приближаться к скорости записи (N-K) самого медленного диска в массиве. В stripe же она будет близка к сумме скоростей всех дисков.
Пример:
Предположим, у вас массив из 3 дисков, каждый со скоростью записи 200 МБ/с.
-
Stripe (RAID-0): Теоретическая скорость записи может достигать около 600 МБ/с.
-
RAIDZ1: Теоретическая скорость последовательной записи может быть около 400 МБ/с (2 * 200 МБ/с). Фактическая скорость может быть ниже из-за вычисления чётности. Скорость случайной записи будет значительно ниже из-за "write penalty".
Дополнительные возможности при формировании пула:
В ZFS также поддерживаются вложенные конфигурации RAID, такие как чередование зеркалированных vdev (аналогично RAID 10) или чередование нескольких vdev RAIDZ (аналогично RAID 50 или RAID 60). Это позволяет объединить преимущества различных уровней RAID для удовлетворения конкретных потребностей в производительности и резервировании. Гибкость ZFS позволяет создавать сложные вложенные конфигурации RAID, предлагая широкий спектр возможностей для адаптации решений хранения к очень специфическим требованиям, хотя и с повышенной сложностью управления и понимания. Комбинируя различные типы виртуальных устройств (например, зеркала и группы RAIDZ) в пул ZFS, администраторы могут создавать высоконастраиваемые архитектуры хранения, которые балансируют производительность, резервирование и емкость способами, которые могут быть недоступны при использовании традиционного аппаратного RAID.
При создании пула (zpool) также можно настроить специальные vdev для служебных целей, что может значительно повысить производительность определенных операций:
-
Логирование (ZIL/SLOG): Для ускорения синхронных записей используется Журнал Намерений ZFS (ZIL - ZFS Intent Log). По умолчанию ZIL размещается в основном пуле хранения. Однако для существенного прироста производительности синхронных операций (важно для баз данных, NFS) ZIL можно вынести на отдельное быстрое устройство – SLOG (Separate Log), обычно это высокопроизводительный SSD с низкими задержками и защитой от потери питания (PLP). SLOG не кэширует сами данные, а лишь временно хранит записи о синхронных операциях, пока они не будут безопасно записаны в основной пул.
-
Резервирование дисков (Hot Spares): В пуле можно назначить один или несколько дисков в качестве горячего резерва. В случае выхода из строя диска в одном из vdev пула, ZFS автоматически (если настроена опция autoreplace) или по команде администратора начнет процесс ресильверинга на диск горячего резерва, восстанавливая избыточность. Запасные диски должны быть идентичны заменяемым или больше их по размеру. Они не используются для хранения данных до момента сбоя (актуально для RAIDZ).
-
Кэширование (L2ARC): Кроме основного кэша в оперативной памяти (ARC), ZFS поддерживает кэш второго уровня – L2ARC (Level 2 Adaptive Replacement Cache). L2ARC размещается на быстрых устройствах (обычно SSD) и хранит блоки данных, вытесненные из ARC, тем самым расширяя общую емкость кэша чтения.
-
vdev для метаданных (Special VDEV for Metadata): В ZFS можно создать специальный vdev, предназначенный исключительно для хранения метаданных (информации о структуре и организации данных в файловой системе). Это может быть полезно для пулов со сложной структурой каталогов или большим количеством мелких файлов, так как ускоряет операции с метаданными и ввод-вывод небольших блоков.
-
vdev для дедупликации (Special VDEV for Deduplication Table): Если используется функция дедупликации ZFS, таблицы дедупликации (DDT) могут быть вынесены на отдельный специальный vdev. Это крайне важно, так как производительность дедупликации сильно зависит от скорости доступа к DDT. Рекомендуется, чтобы такой vdev был очень быстрым и достаточно емким (например, X GiB для каждого X TiB общего хранилища).
Механизмы кэширования: повышение производительности
ZFS включает многоуровневую систему кэширования для повышения производительности чтения и записи:
-
Адаптивный кэш замещения (ARC)
ARC является основным кэшем чтения в памяти, который динамически адаптируется к шаблонам рабочей нагрузки. ARC кэш хранится в оперативной памяти. ARC имеет метаданные – списки для отслеживания недавно и часто используемых данных, а также вытесненных записей. Адаптивная природа ARC позволяет ZFS эффективно использовать доступную оперативную память для кэширования, что приводит к значительному повышению скорости чтения для часто используемых данных. ARC, отслеживая как недавно, так и часто используемые данные, может лучше адаптироваться к различным рабочим нагрузкам. -
Адаптивный кэш замещения второго уровня (L2ARC)
L2ARC является вторичным дисковым кэшем чтения, который хранится на SSD, расширяя емкость ARC. L2ARC хранит данные, вытесненные из ARC, предоставляя еще один уровень кэширования для менее часто используемых, но все еще важных данных. Когда основной кэш RAM (ARC) заполнен, и запрошенный фрагмент данных не найден там, система обычно должна считывать его с гораздо более медленных жестких дисков. -
Журнал намерений ZFS (ZIL) и отдельный журнал (SLOG)
ZIL представляет собой журнал записи, предназначенный для ускорения синхронных записей. ZIL обеспечивает целостность данных, регистрируя синхронные операции записи до их фиксации в основном пуле хранения. Отдельное устройство журнала (SLOG), обычно SSD, может использоваться для дальнейшего повышения производительности синхронных записей путем переноса ZIL на более быстрое устройство. ARC и L2ARC являются кэшами только для чтения, в то время как SLOG специально предназначен для ускорения синхронных записей и используется для аварийного восстановления. Механизмы ZIL и SLOG устраняют узкое место производительности, часто связанное с синхронными записями. Синхронные записи требуют от системы подтверждения безопасной записи данных в постоянное хранилище, прежде чем продолжить. Это может быть узким местом производительности с традиционными жесткими дисками. ZIL действует как временный, быстрый журнал для этих записей. Сначала записывая в ZIL (особенно если это на быстром SSD в качестве SLOG), система может быстро подтвердить завершение записи, и затем данные записываются в основной пул хранения асинхронно. Это значительно повышает скорость реагирования приложений, которые полагаются на синхронные записи.
Для достижения оптимальной производительности кэша рекомендуется на 50 ГБ L2ARC кэша использовать не менее 1 ГБ ARC кэша.
Таблица 3: Механизмы кэширования ZFS
Тип кэша |
Расположение |
Используется для |
Назначение |
Ключевые преимущества |
ARC |
Оперативная память |
Чтение |
Основной кэш чтения, адаптивный к рабочей нагрузке |
Быстрый доступ к часто используемым данным, повышение производительности чтения |
L2ARC |
рекомендуется использовать SSD |
Чтение |
Вторичный кэш чтения, расширяет ARC |
Увеличение размера кэша чтения, повышение производительности при больших рабочих наборах |
ZIL |
Пул/SLOG |
Запись |
Журнал транзакций для синхронных записей |
Обеспечение целостности данных, ускорение синхронных записей |
SLOG |
SATA/NVMe SSD |
Запись |
Отдельное устройство журнала для ZIL |
Дальнейшее ускорение синхронных записей, снижение задержки |
Подробнее о ZFS:
Первая часть статьи находится по ссылке.