ВведениеС самого начала появления ZFS, я записался в ряды ее поклонников, и до сих пор ни разу не пожалел об этом. И на страницах opennet.ru я уже успел [[http://www.opennet.dev/tips/info/2321.shtml поделиться]] приятными моментами ее использования на OS FreeBSD.
Сегодня речь пойдет о возможностях непрерывной репликации ZFS между хостами FreeBSD.
++ Цели
Лично мне это стало не просто полезным, а необходимым, как только возникла задача использования виртуальных окружений, и в рамках одного физического сервера создавалась группа виртуальных серверов.
Первоначальная задумка выглядела следующим образом:
* Основной сервер виртуализации
* Сервер горячей замены (по своим характеристикам близкий, но не идентичный основному)
* Коммерческое ПО для виртуализации, не предполагалось, только OpenSource.
Задача абсолютной бесперебойной работы не ставилась, основной критерий - быстрое (в пределах 5 минут) время восстановления IT сервисов в случае отказа основного сервера, с минимальной потерей пользовательских данных. Другими словами, если основной сервер выходит из строя, то все данные пользователей, сохраненные за несколько минут до отказа, не должны быть утеряны.
Вариант с общим NAS, разделяемый между серверами виртуализации, по ряду причин, в том числе и финансовых, так же не рассматривался.
Таким образом, данную конфигурацию можно кратко охарактеризовать, как среда виртуализации начального уровня с элементами отказоустойчивости.
++ Средства
В качестве хост системы выступает [[http://www.freebsd.org/releases/8.1R/announce.html FreeBSD 8.1]] с гипервизором [[http://www.virtualbox.org VirtualBox OSS]].
Я не буду подробно останавливаться на процессе установки и настройки VirtualBox, скажу только то, что оба сервера и основной и резервный имеют идентичное ПО, а все конфигурации и образы виртуальных серверов расположены внутри ZFS с точкой монтирования /var/IMAGES.
В таком виде, задача обеспечения отказоустойчивости сводится к синхронизации содержимого /var/IMAGES с основного сервера на резервный, чтобы в случае отказа, оставалась возможность запуска всех серверов на резервном сервере из актуальных образов.
Очевидным является тот факт, что чем чаще происходит синхронизация, тем лучше. Так же очевидно что [[http://ru.wikipedia.org/wiki/Rsync rsync]], не смотря на все его прелести, не способен обеспечить синхронизацию заданными выше временными рамками.
Беглый поиск выявляет упоминания о [[http://hub.opensolaris.org/bin/view/Project+avs/WebHome коммерческих реализациях zfs репликации]] а так же стандартных возможностях ZFS создания, и что самое важное, обмена ими между хостами посредством zfs send/receive. Об этом упоминалось, в том числе и на [[http://www.opennet.dev/opennews/art.shtml?num=18823 страницах opennet]].
Именно zfs send/receive будет использован для непрерывной репликации в режиме близкому к реальному времени.
Репликацией должен заниматься скрипт, запускаемый из cron, интервал запуска 1 минута.
Скрипт запускается на резервном сервере и должен:
* Создать новый снапшот на основном сервере.
* Все снапшоты, задействованные в процессе репликации, должны иметь некую отличительную особенность (префикс в своем имени).
* Выявить самый свежий общий снапшот, относительно которого, можно провести инкрементальную репликацию. В случае его отсутствия провести полную репликации.
* Провести репликацию через send/receive
* Удалить неиспользуемые снапшоты.
* Запротоколировать все свои действия.
Как видно из краткого плана мероприятий, резервному серверу придется запускать команды на основном. SSH замечательно справиться с этим, но нужно иметь ввиду что:
* запускать через скрипт команды на удаленном сервере от имени рута ( а значит хранить или пароль или ключ рута) не слишком хорошая идея.
* ZFS на FreeBSD до сих пор не дружит с [[http://blogs.sun.com/marks/entry/zfs_delegated_administration ZFS Delegated Administration]]
Учитывая эти два факта, следует завести на основном сервере на привилегированного пользователя и выполнять команды zfs через sudo , разрешив ему необходимый минимум.
В файле /usr/local/etc/sudoers.d/zfs_replication определяем для пользователя следующие разрешения
synczfs ALL = NOPASSWD : /sbin/zfs snapshot *, /sbin/zfs send *,/sbin/zfs list *,/sbin/zfs destroy *
А теперь непосредственно скрипт /root/zfs-nrt-replication.sh
#!/bin/sh
REMOTE_HOST="master.local"
FS="/var/IMAGES"
REMOTE_POOL="tank0"
LOCAL_POOL="tank0"
SNAPSHOTMARK="SYNC-"
SSHKEY="/root/syncimages_id"
SSHFLAGS="-i $SSHKEY -o CheckHostIP=no -o StrictHostKeyChecking=no \
-o IdentitiesOnly=yes -o BatchMode=yes -o GlobalKnownHostsFile=/dev/null -l synczfs"
SSHCMD="/usr/bin/ssh $SSHFLAGS $REMOTE_HOST sudo "
INCREMENTAL=""
(
echo "Snapshoting remote FS"
$SSHCMD "zfs snapshot -r $REMOTE_POOL$FS@$SNAPSHOTMARK`uuidgen`"
RECENT_COMMON_SNAPSHOT=""
for R in `$SSHCMD zfs list -H -o name -s creation -t snapshot -r $REMOTE_POOL$FS | grep $REMOTE_POOL$FS@`
do
for L in `zfs list -H -o name -s creation -t snapshot -r $LOCAL_POOL$FS | grep $LOCAL_POOL$FS@`
do
if [ "${R##*@}" = "${L##*@}" ]; then
RECENT_COMMON_SNAPSHOT=${R##*@}
INCREMENTAL="-I $REMOTE_POOL$FS@$RECENT_COMMON_SNAPSHOT"
fi
done
REMOTE_LATEST_SNAPSHOT=${R##*@}
done
echo "Syncronizing remote FS to local"
echo "zfs send -R $INCREMENTAL $REMOTE_POOL$FS@$REMOTE_LATEST_SNAPSHOT"
$SSHCMD "zfs send -R $INCREMENTAL $REMOTE_POOL$FS@$REMOTE_LATEST_SNAPSHOT" | \
/usr/local/bin/pipemeter --autooff --blocksize 16M --interval 60 --log | zfs receive -dF $LOCAL_POOL
if [ $? -eq 0 ]; then
echo "Cleaning useless remote snapshots"
$SSHCMD "zfs list -r -t snapshot -o name -H $REMOTE_POOL$FS | grep \"$SNAPSHOTMARK\" | \
egrep -v \"@($RECENT_COMMON_SNAPSHOT|$REMOTE_LATEST_SNAPSHOT)\" | xargs -I% sudo zfs destroy %"
fi
echo "Done."
) 2>&1 | logger -s -p ftp.info -t SYNCZFS
Сам скрипт запускается на резервном сервере из cron следующим образом
*/1 * * * * root /usr/sbin/daemon -p /var/run/zfs-sync.pid -f /root/zfs-nrt-replication.sh > /dev/null
Итак, на резервном сервере скрипт запускается каждую минуту, но если он еще не закончил свое выполнение с прошлого запуска, то попытка пропускается. Весь вывод скрипта направляется в лог-файл /var/log/xferlog. Для более наглядной оценки скорости используется дополнительное ПО [[http://www.freshports.org/sysutils/pipemeter/ pipemeter]], в результате чего в лог файл, с минутным интервалом, добавляется информация об объеме передаваемых данных, а так же скорости обмена.
Дополнительно, можно настроить [[http://andyleonard.com/2010/04/07/automatic-zfs-snapshot-rot.../ автоматический снапшотинг]], чтобы иметь версии виртуальных машин различной степени давности (часовой, дневной, недельной и т.д.). Эти версии так же будут реплицироваться на резервный сервер.
И теперь, в случае обнаружения отказа в работе основного сервера, администратору остается запустить виртуальную машину на резервном сервере, но и этот процесс так же можно автоматизировать, но это материал еще для одной статьи :)
URL:
Обсуждается: http://www.opennet.dev/tips/info/2499.shtml