SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor

Самовосстановление ZFS на VPS с одним диском

ZFS проверяет контрольную сумму каждого блока, но починить его может только при наличии второй копии. Что это значит для VPS с одним диском и где тогда живёт план восстановления.

Короткий ответ

Самовосстановление ZFS на VPS с одним диском работает ровно наполовину: повреждение будет найдено, но не исправлено. Каждый блок в пуле хранится вместе с контрольной суммой, и любое чтение эту сумму пересчитывает. Починить блок ZFS может только тогда, когда доступна вторая исправная копия: половина зеркала, расчёт чётности raidz или вторая копия при copies=2. На одном virtio-диске второй копии данных нет. ZFS назовёт имя повреждённого файла и вернёт приложению ошибку ввода-вывода вместо испорченных байт. Значит, план восстановления при такой раскладке живёт не в пуле, а в резервной копии на другом хосте.

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

Из чего состоит самовосстановление ZFS

Механизм удобно разложить на четыре шага. Первые три работают на любом пуле, включая пул из одного диска. Четвёртый требует избыточности, и именно его на одном диске нет.

  1. Запись. ZFS считает контрольную сумму блока и кладёт её не рядом с данными, а в указатель на блок (block pointer), который лежит уровнем выше. Дерево ссылок проверяет само себя: каждый узел подтверждает содержимое дочерних.
  2. Чтение. Сумма пересчитывается при каждом чтении и сравнивается с записанной. Совпало, блок уходит приложению. Не совпало, блок считается повреждённым, и счётчик CKSUM у этого устройства растёт.
  3. Полная проверка. Команда zpool scrub читает все занятые блоки и сверяет суммы, не дожидаясь, пока до файла доберётся пользователь. Это единственный способ узнать о повреждении в архиве, который никто не открывает.
  4. Ремонт. ZFS берёт исправную копию блока, отдаёт её приложению и сразу перезаписывает испорченную. Копия приходит из второй половины зеркала, из чётности raidz или из второй ditto-копии при copies=2.

По умолчанию для данных используется fletcher4, это и есть checksum=on. Криптографические алгоритмы (sha256, blake3) считаются дольше и нужны прежде всего дедупликации. Какие из них знает ваша сборка, зависит от версии OpenZFS: на сентябрь 2026 blake3 есть в ветках 2.2 и новее, а точную версию у себя покажет zfs version.

sudo apt install -y zfsutils-linux
zfs version
zpool status -v tank

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

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

Метаданные лечатся даже на одном диске, данные нет

Из-за этой тонкости на форумах спорят до бесконечности. Свойство copies по умолчанию равно 1 только для данных. Метаданные ZFS пишет в двух экземплярах, а служебные метаданные пула в трёх, и на одном устройстве разносит их по разным областям диска. Такие дубликаты называются ditto-блоки. Поэтому повреждение каталога или указателя на пуле из одного диска ZFS часто действительно исправляет сама, а повреждение блока с содержимым файла не исправляет никогда.

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

Почему на одном диске ремонт невозможен

ZFS не отдаёт приложению блок, который не сошёлся по сумме. Вместо данных вызов read() получает EIO, cp печатает ошибку ввода-вывода, а веб-сервер отвечает пятисотой ошибкой. Для сравнения, ext4 и XFS вернут то, что отдал диск, потому что проверять им нечем: контрольные суммы там есть у журнала и метаданных, но не у содержимого файлов. Поведение ZFS выглядит грубее, а на деле оно единственно честное. Молча отданный испорченный байт уедет в бэкап, в архив и в базу, и там будет жить как правильный.

Заменить единственный диск на зеркало позже можно: zpool attach tank <старое устройство> <новое устройство> превращает одиночный vdev в зеркало и запускает ресилверинг. Это одна из немногих свобод, которые остаются после создания пула. Часть решений фиксируется навсегда, и какие параметры пула нельзя поменять после создания стоит прочитать до первой команды zpool create, а не после.

Где в zpool status искать CKSUM и строку errors

Команда zpool status -v печатает таблицу устройств пула со столбцами READ, WRITE и CKSUM. Первые два это ошибки ввода-вывода при чтении и записи. Третий это счётчик блоков, которые не сошлись по контрольной сумме. Любое ненулевое значение в CKSUM означает, что ZFS получила с устройства байты, которых там быть не должно.

Под таблицей идёт строка, которая начинается с errors:. На здоровом пуле она сообщает, что известных ошибок данных нет. Если ошибка постоянная, то есть исправить блок было нечем, ZFS добавляет раздел с перечислением пострадавших объектов. Обычно это путь вида tank/data/файл, но для объекта без имени (уже удалённый файл или метаданные) вы увидите шестнадцатеричный идентификатор в угловых скобках. Такой идентификатор без пути обычно говорит, что пострадала служебная структура, и это худший вариант из возможных.

Для мониторинга удобнее zpool status -x: она печатает только нездоровые пулы, поэтому её легко повесить в cron и получать письмо лишь когда есть о чём писать. Штатные уведомления делает демон ZED: в /etc/zfs/zed.d/zed.rc задайте ZED_EMAIL_ADDR, при желании включите ZED_NOTIFY_VERBOSE=1 и перезапустите службу командой sudo systemctl restart zfs-zed. Проверить, что канал работает, проще всего на любом безобидном событии пула, например на запуске и завершении скраба.

Счётчики сбрасывает zpool clear tank. Она не восстанавливает ни один байт, она только обнуляет статистику и убирает пометку о деградации. Сохраните вывод zpool status -v в файл до сброса, иначе вы потеряете единственную запись о том, какие файлы пострадали.

Откуда на VPS с одним диском берётся ненулевой CKSUM. Умирающая NVMe, ошибки на уровне хранилища провайдера, потери и таймауты у сетевого диска, память без ECC на гипервизоре. Разница между локальным и сетевым устройством здесь принципиальна, потому что у них разные виды отказа: чем локальный NVMe отличается от сетевого хранилища на VPS объясняет, чего ждать от каждого. Параллельно смотрите на сам диск: мониторинг здоровья диска на VPS показывает, как читать SMART в гостевой системе и что из него вообще доступно виртуальной машине.

Помогает ли отказоустойчивое хранилище провайдера

Нет, и это самое дорогое заблуждение в теме. Под вашим виртуальным диском у провайдера может быть RAID 10, Ceph или другая репликация. Гостевая система видит одно блочное устройство. У ZFS нет способа сказать этому устройству: «этот блок битый, дай мне другую реплику». Такого интерфейса не существует ни в virtio-blk, ни в SCSI. Для ZFS там один vdev и одна копия данных.

Есть и вторая причина, менее очевидная. Слой хранения провайдера сохраняет то, что ему прислали. Если байты испортились выше него, в памяти гостя, в драйвере, в гипервизоре или в самой прошивке диска до записи, все реплики честно сохранят испорченный вариант. Репликация отвечает на вопрос «что делать, когда диск умер». Она не отвечает на вопрос «что делать, когда байты изменились». ZFS отвечает как раз на второй, и на одном диске отвечает половиной ответа: обнаружением.

К этому добавьте случаи, где избыточность провайдера не помогает вовсе: rm -rf от вашего же скрипта, шифровальщик, ошибка в миграции, блокировка аккаунта. Про границу между избыточностью и резервной копией написано отдельно: считается ли storage VPS резервной копией и чем снапшоты провайдера отличаются от бэкапов закрывают этот вопрос для арендованного железа.

Что даёт copies=2 и чего не даёт

Свойство copies заставляет ZFS писать каждый блок датасета несколько раз и разносить копии по устройству как можно дальше друг от друга. На пуле из одного диска это единственный способ дать механизму ремонта вторую копию данных.

sudo zfs set copies=2 tank/docs
zfs get -r copies tank

Четыре ограничения, о которых нужно знать заранее.

  • Свойство действует только на новые записи. Файлы, которые уже лежат в датасете, останутся в одной копии, пока их не перезапишут. Чтобы покрыть существующие данные, создайте новый датасет с copies=2 и переложите данные в него.
  • Место расходуется вдвое, и это видно в zfs list и в квотах: обе копии считаются занятым местом того же датасета.
  • Записи становится вдвое больше. На тарифе с ограниченным IOPS это заметно.
  • Копии живут на одном устройстве. Диск умер, ушёл хост, закрылся аккаунт, и обе копии пропали одновременно.

То есть copies=2 защищает от локального повреждения (сбойный участок, испорченный блок), но не от потери устройства. Это разумная страховка для небольшого важного датасета, когда второй диск купить нельзя. Это не замена бэкапу ни при каких условиях.

Сколько сырого места стоит вторая копия

ChartСырое место на 100 ГБ данных при разных раскладках
The data behind this chart
[
  {
    "config": "1 \u0434\u0438\u0441\u043a, copies=1",
    "raw_gb": 100,
    "spare_copies": 0
  },
  {
    "config": "1 \u0434\u0438\u0441\u043a, copies=2",
    "raw_gb": 200,
    "spare_copies": 1
  },
  {
    "config": "mirror \u0438\u0437 2 \u0434\u0438\u0441\u043a\u043e\u0432",
    "raw_gb": 200,
    "spare_copies": 1
  },
  {
    "config": "raidz1 \u0438\u0437 3 \u0434\u0438\u0441\u043a\u043e\u0432",
    "raw_gb": 150,
    "spare_copies": 1
  }
]

Это арифметика, а не замер: столбец spare_copies показывает, сколько избыточных копий блока ZFS сможет запросить при несовпадении суммы. У раскладки по умолчанию их 0, поэтому ремонта нет. Включение copies=2 поднимает расход до 200 ГБ сырого места на те же 100 ГБ данных, ровно столько же просит зеркало из двух дисков. Разница в том, что зеркало переживает смерть одного устройства, а вторая копия на одном диске не переживает. Самая экономная по месту избыточность здесь у raidz1 из трёх дисков, 150 ГБ, но три диска на бюджетном VPS встречаются редко.

Откуда взяты числа

Для copies=2 и зеркала множитель равен 2 по определению. Для raidz1 из трёх устройств одна треть сырого места уходит на чётность, поэтому на 100 ГБ полезных данных нужно 150 ГБ сырых. Накладные расходы raidz на практике зависят от размера записи и ashift, так что на реальном пуле доступное место будет немного меньше расчётного. Считайте эти 4 строки ориентиром для выбора раскладки, а не обещанием точной ёмкости.

В раскладке raidz есть ещё один важный момент для владельца VPS: число дисков в группе фиксируется при создании. Расширение raidz добавлением устройства появилось в OpenZFS 2.3, и есть ли оно у вас, покажет zfs version. Планируйте так, будто его нет.

Снимок на том же пуле не является резервной копией

Снимки ZFS дешёвые, мгновенные и очень полезные. Они спасают от вашей собственной ошибки: удалили каталог, сломали конфиг, обновление испортило базу. Про механизм есть отдельный разбор: как работают снимки, клоны и откат в ZFS.

Чего снимок не делает: он не создаёт второй экземпляр данных. Снимок это набор ссылок на те же блоки внутри того же пула. Блок, который не сошёлся по сумме, испорчен и для снимка тоже. Пул умер вместе с диском, и все снимки умерли с ним.

Рабочая схема для одного диска складывается из двух частей. Снимки по расписанию на месте, чтобы быстро откатывать ошибки. Репликация снимков на другой хост, чтобы иметь второй экземпляр данных: отправка снимков через zfs send на storage VPS описывает инкрементальную передачу и то, как проверять, что принимающая сторона действительно получила поток. Если ZFS на приёмной стороне нет, ту же задачу решают бэкапы на VPS с помощью restic, где дедупликация и проверка целостности живут в самом репозитории.

Скраб превращает ZFS в раннее предупреждение

Без скраба обнаружение работает только для тех блоков, которые кто-то читает. Архив, к которому не обращались полгода, портится молча.

sudo zpool scrub tank
zpool status tank
sudo zpool scrub -s tank

Вторая команда покажет ход проверки и оценку времени, третья останавливает её, если нагрузка мешает работе. В пакете zfsutils-linux обычно уже есть готовое расписание, и проверить, что именно включено у вас, стоит явно: посмотрите systemctl list-timers 'zfs-*' и содержимое /etc/cron.d. Для сетевого диска время запуска важнее, чем для локального: скраб читает весь занятый объём и создаёт ровную долгую нагрузку. Как часто запускать проверку на небольшом пуле и почему ежедневный скраб это не лучше ежемесячного, разобрано в расписании скраба для маленьких пулов.

Смысл скраба на одном диске другой, чем на зеркале. На зеркале он ремонтирует. На одном диске он сообщает. Это всё равно ценно: вы узнаёте о повреждении пока живы бэкапы нужной глубины, а не в день восстановления.

Что делать, когда ZFS назвала повреждённый файл

  1. Сохраните вывод zpool status -v в файл, например zpool status -v tank > ~/zfs-incident.txt. Это список пострадавших объектов, и после zpool clear его уже не будет.
  2. Восстановите перечисленные файлы из бэкапа. Ремонта средствами пула не будет, поэтому это единственный путь.
  3. Проверьте, идёт ли речь о единичном случае. Запустите скраб и дождитесь его окончания. Растущий CKSUM на новой проверке означает, что устройство или слой под ним продолжает портить данные.
  4. Посмотрите на здоровье диска и на события гипервизора, а затем откройте тикет провайдеру со сохранённым выводом. Ненулевой CKSUM это конкретный факт, с которым в поддержке говорить проще, чем с жалобой на медленный сервер.
  5. Только после этого делайте zpool clear tank, чтобы следующая ошибка была видна как новая.
  6. Если ошибки повторяются, планируйте переезд, а не борьбу. Порядок действий описан в переносе сервера на новый VPS, и на испорченном пуле его лучше выполнять из бэкапа, а не копированием текущих файлов.

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

Второй диск или бэкап: как решить, когда бюджет один

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

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

Бэкап на другой хост не даёт самовосстановления и не держит сервис на ногах, зато переживает всё: диск, хост, провайдера, ваш собственный rm -rf. Если денег хватает только на одно, берите бэкап на другой хост. Выбор между вариантами дискового пространства под него разобран в сравнении дешёвых терабайтов у storage VPS, блочных и объектных хранилищ.

Порядок, который стоит того на практике: сначала внешний бэкап, затем регулярный скраб с уведомлениями, затем copies=2 для маленького критичного датасета, если второй диск всё ещё не по карману, и только потом зеркало ради времени работы сервиса. Зеркало стоит денег каждый месяц и решает задачу доступности, а не задачу сохранности.

Чек-лист для пула на одном диске

  • Не рассчитывайте на ремонт. Проверьте, что zpool status показывает один vdev, и относитесь к пулу как к одной копии данных.
  • Включите уведомления ZED или проверку zpool status -x по расписанию. Обнаружение без оповещения бесполезно.
  • Держите скраб на расписании и убедитесь, что он действительно завершается, а не отменяется каждый раз нагрузкой.
  • Настройте снимки для откатов и репликацию снимков на другой хост для восстановления. Это две разные задачи.
  • Раз в квартал восстановите один файл из бэкапа и сверьте его. Непроверенный бэкап это предположение, а не план.
  • Записывайте каждый инцидент с ненулевым CKSUM. Два случая на одном устройстве это уже повод менять сервер.

FAQ

Самовосстанавливается ли ZFS на одном диске?

Обнаружение работает полностью, ремонт данных нет. Контрольная сумма каждого блока проверяется при чтении и при скрабе, поэтому ZFS точно скажет, какой файл повреждён, и вернёт ошибку ввода-вывода вместо испорченных байт. Заменить блок ей нечем, потому что вторая копия данных на одном vdev отсутствует. Исключение это метаданные: они по умолчанию пишутся в двух или трёх экземплярах, поэтому их повреждение на одном диске часто исправляется автоматически.

Что означает ненулевое значение CKSUM в zpool status?

Это число блоков, которые не сошлись с записанной контрольной суммой. Причина лежит ниже ZFS: деградирующий носитель, ошибки слоя хранения провайдера, потери у сетевого диска, память без ECC. Если ниже в выводе строка errors: перечисляет конкретные пути, эти файлы восстановить средствами пула нельзя, нужен бэкап. Сохраните вывод zpool status -v до zpool clear, иначе список пострадавших объектов будет потерян.

Стоит ли включать copies=2 на VPS с одним диском?

Иногда, и только с ясным пониманием цены. Свойство даёт ZFS вторую копию данных, поэтому локальное повреждение станет исправимым, но место и объём записи удваиваются, действует оно лишь на новые записи, и обе копии исчезают вместе с диском. Разумное применение это небольшой важный датасет, когда второй диск купить нельзя. Как замену внешнему бэкапу использовать его нельзя.

Заменяет ли отказоустойчивое хранилище провайдера избыточность в пуле?

Нет. Гостевая система видит одно блочное устройство, и у ZFS нет способа запросить у него другую реплику блока: такого интерфейса в virtio и SCSI не существует. Репликация провайдера защищает от смерти физического диска, а не от изменившихся байт, и если данные испортились выше слоя хранения, все реплики сохранят испорченный вариант. Вторую копию, которой ZFS реально может воспользоваться, даёт только зеркало, raidz или copies=2 внутри пула.

#zfs#storage#backups#data-integrity#vps