У меня есть один пул zfs, содержащий несколько zvol и наборов данных, некоторые из которых также вложены. Все наборы данных и zvol периодически делаются снимками с помощью zfs-auto-snapshot. Все наборы данных и zvol также имеют некоторые вручную созданные снимки.
Я настроил удаленный пул, на котором из-за нехватки времени первоначальное копирование по локальной высокоскоростной сети с помощью zfs send -R не было завершено (некоторые наборы данных отсутствуют, некоторые наборы данных имеют устаревшие или отсутствующие моментальные снимки).
Теперь пул физически удален и использует медленное соединение, и мне необходимо периодически синхронизировать удаленный пул с локальным пулом, то есть данные, присутствующие в локальном пуле, должны быть скопированы в удаленный пул, данные, удаленные из локального пула, должны быть удалены из удаленного пула, а данные, присутствующие в удаленном пуле, но не в локальном пуле, должны быть удалены из удаленного пула, под данными понимаются «zvols», «datasets» или «snapshots».
Если бы я делал это между двумя обычными файловыми системами с помощью rsync, это было бы «-axPHAX --delete» (именно так я на самом деле делаю резервное копирование некоторых систем).
Как настроить задачу синхронизации, чтобы удаленные zvols и наборы данных пула (включая их моментальные снимки) могли быть синхронизированы с локальными zvols, наборами данных и моментальными снимками?
Я бы хотел избежать передачи данных по SSH из-за низкой пропускной способности SSH; вместо этого я бы предпочел mbuffer или iscsi.
решение1
Отказ от ответственности: Поскольку я никогда не использовал zvols, я не могу сказать, отличаются ли они в репликации от обычных файловых систем или снимков. Я предполагаю, что они отличаются, но не верьте мне на слово.
Ваш вопрос на самом деле состоит из нескольких вопросов, я постараюсь ответить на них по отдельности:
Как реплицировать/зеркалировать весь пул в удаленное местоположение
Необходимо разбить задачу на две части: во-первых, первоначальная репликация должна быть завершена, после этого возможна инкрементальная репликация,если только вы не вмешиваетесь в свои репликационные снимки. Чтобы включить инкрементальную репликацию, вам нужно сохранить последние снимки репликации, все, что было до этого, можно удалить. Если вы удалите предыдущий снимок, zfs recv
возникнет ошибка и репликация будет прервана. В этом случае вам придется начинать все заново, поэтому постарайтесь этого не делать.
Если вам просто нужны правильные варианты, то вот они:
zfs send
:-R
: отправить все в указанном пуле или наборе данных (рекурсивная репликация, необходимая все время, включает-p
). Кроме того, при получении все удаленные исходные снимки удаляются в месте назначения.-I
: включить все промежуточные снимки между последним снимком репликации и текущим снимком репликации (требуется только при инкрементных отправках)
zfs recv
:-F
: расширение целевого пула, включая удаление существующих наборов данных, которые удалены на источнике-d
: отбросить имя исходного пула и заменить его именем целевого пула (остальные пути файловой системы будут сохранены и при необходимости также созданы)-u
: не монтировать файловую систему в месте назначения
Если вы предпочитаете полный пример, вот небольшой скрипт:
#!/bin/sh
# Setup/variables:
# Each snapshot name must be unique, timestamp is a good choice.
# You can also use Solaris date, but I don't know the correct syntax.
snapshot_string=DO_NOT_DELETE_remote_replication_
timestamp=$(/usr/gnu/bin/date '+%Y%m%d%H%M%S')
source_pool=tank
destination_pool=tank
new_snap="$source_pool"@"$snapshot_string""$timestamp"
destination_host=remotehostname
# Initial send:
# Create first recursive snapshot of the whole pool.
zfs snapshot -r "$new_snap"
# Initial replication via SSH.
zfs send -R "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"
# Incremental sends:
# Get old snapshot name.
old_snap=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$source_pool"@"$snapshot_string" | tail --lines=1)
# Create new recursive snapshot of the whole pool.
zfs snapshot -r "$new_snap"
# Incremental replication via SSH.
zfs send -R -I "$old_snap" "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"
# Delete older snaps on the local source (grep -v inverts the selection)
delete_from=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$snapshot_string" | grep -v "$timestamp")
for snap in $delete_from; do
zfs destroy "$snap"
done
Используйте что-то более быстрое, чем SSH
Если у вас достаточно защищенное соединение, например, туннель IPSec или OpenVPN, и отдельная VLAN, которая существует только между отправителем и получателем, вы можете переключиться с SSH на незашифрованные альтернативы, такие как mbuffer.как описано здесь, или вы можете использовать SSH со слабым шифрованием или без него и отключенным сжатием,который подробно описан здесь. Также был сайт о том, как перекомпилировать SSH, чтобы он работал намного быстрее, но, к сожалению, я не помню URL-адрес — я отредактирую его позже, если найду.
Для очень больших наборов данных и медленных соединений может быть также полезно сначала передавать данные через жесткий диск (используйте зашифрованный диск для хранения zpool и передавайте его в запечатанном пакете через курьера, по почте или лично). Поскольку метод передачи не имеет значения для send/recv, вы можете перенаправить все данные на диск, экспортировать пул, отправить диск по назначению, импортировать пул и затем передавать все инкрементные отправки по SSH.
Проблема с испорченными снимками
Как было сказано ранее, если вы удалите/измените снимки репликации, вы получите сообщение об ошибке
cannot send 'pool/fs@name': not an earlier snapshot from the same fs
это означает, что либо ваша команда была неверной, либо вы находитесь в несогласованном состоянии, в котором вам необходимо удалить снимки и начать все заново.
Это имеет ряд негативных последствий:
- Вы не можете удалить моментальный снимок репликации, пока новый моментальный снимок репликации не будет успешно передан. Поскольку эти моментальные снимки репликации включают состояние всех других (более старых) моментальных снимков, пустое пространство удаленных файлов и моментальных снимков будет восстановлено только после завершения репликации. Это может привести к временным или постоянным проблемам с пространством в вашем пуле, которые вы можете исправить только путем перезапуска или завершения полной процедуры репликации.
- У вас будет много дополнительных снимков, что замедлит команду list (за исключением Oracle Solaris 11, где это было исправлено).
- Возможно, вам придется защитить снимки от (случайного) удаления, за исключением самого скрипта.
Существует возможное решение этих проблем, но я сам его не пробовал. Вы можете использовать zfs bookmark
, новую функцию в OpenSolaris/illumos, созданную специально для этой задачи. Это освободит вас от управления снимками. Единственным недостатком является то, что в настоящее время это работает только для отдельных наборов данных, а не рекурсивно. Вам придется сохранить список всех ваших старых и новых наборов данных, а затем пройтись по ним циклом, добавляя в закладки, отправляя и получая их, а затем обновляя список (или небольшую базу данных, если вам так больше нравится).
Если вы попробуете воспользоваться маршрутом закладок, мне было бы интересно услышать, как он у вас получился!
решение2
Лично я бы составил список zvols, наборов данных и т. д. на удаленном сервере, которыйнеиметь актуальные снимки, а затем обновлять их с помощью zfs send
, даже если это занимает много времени и использует большую пропускную способность.
Тогда я мог бы просто продолжать использовать zfs send
его и не изобретать велосипед, написав свой собственный код синхронизации. rsync
Это хорошо для старых файловых систем, но zfs send
гораздо лучше для zfs — он знаетточнокакие блоки изменились в снимке и отправляеттольков то время как rsync должен сравнивать отдельные файлы и/или временные метки между локальными и удаленными серверами. То же самое относится и к btrfs send
пулам BTRFS.
Если у вас есть только небольшое количество снимков, которые нужно обновить, это можно сделать вручную. В противном случае, чтобы сделать это автоматически, вам нужен список последних локальных снимков и удаленных снимков, а также скрипт для сравнения версий, а затем zfs send
локальных снимков, которые устарели на сервере rmeote.
Этого будет достаточно, если вас интересует только последний снимок для каждого набора данных. Если вас интересуют все предыдущие снимки, очевидно, ваш скрипт должен будет обрабатывать и их тоже... и это становится НАМНОГО сложнее. В некоторых случаях вам, возможно, придется откатиться на удаленном сервере, чтобы вы могли повторно отправить промежуточные/отсутствующие снимки.
Если вам нужно безопасное соединение с удаленным сервером, у вас нет выбора, кроме как использовать ssh
— или, возможно, настроить туннель с помощью openvpn
или что-то в этом роде и использовать netcat
.
решение3
Взгляните на `zrepl' на FreeBSD, который может сделать вашу жизнь, и жизнь любого человека, намного проще. Он был представлен несколько дней назад на BSDCan2018 в Оттаве. Он выглядит многообещающим и может быть решением ваших проблем
решение4
zrep — это хорошее комплексное решение, в котором также есть документация и советы о том, как добиться более быстрой передачи данных, чем простая передача данных по SSH.
https://github.com/bolthole/zrep
он также кроссплатформенный: поддерживается на Linux, FreeBSD и Solaris/Illumos