Создание отказоустойчивого хранилища на базе FreeBSD или FreeNAS с использованием ZFS, HAST и CARP Начиная с FreeBSD 8.1 в состав включена поддержка системы репликации устройств хранения данных HAST (Highly Avalable STorage), позволяющей создавать высоконадежные конфигурации, в которых данные синхронизированы между несколькими узлами. HAST реализован в виде работающего на уровне пользователя демона hastd, использующего стандартный класс GEOM Gate для обработки запросов ввода/вывода. Hastd, обеспечивает синхронную репликацию блочных устройств поверх TCP/IP сетей, независимо от типа накопителя и файловой системы. HAST предусматривает возможность быстрого восстановления после сбоя, причём, при выходе из строя первичного master-узла, его функции могут быть делегированы slave-узлу. После проверки и монтирования UFS раздела или импорта ZFS пула на поврежденном узле, система автоматически синхронизирует внесенные за время восстановления изменения и продолжит работу без потери данных. Для быстрого развёртывания хранилищ удобно использовать дистрибутив FreeNAS. К сожалению в настоящее время FreeNAS не поддерживает HAST из коробки, но так как во FreeNAS используются стандартные компоненты FreeBSD 8.x, ни что не мешает самостоятельно вручную создать и надстроить работу подобных хранилищ. После первой загрузки FreeNAS настроим параметры сетевого доступа и DNS. Первый узел freenas1 будет иметь IP 192.168.137.31, а второй freenas2 - 192.168.137.32. После первичной типовой настройки подключимся к shell. Настройка узла HAST Перемонтируем корневой раздел для обеспечения возможности записи: Code: mount -uw / Создадим массив хранения RAID3 из дисков da1, da2, da3. Code: graid3 label gr0raid3 da1 da2 da3 В итоге будет создано устройство /dev/raid3/gr0raid3 Включим поддержку CARP и активируем демон hastd: Code: cat <<EOF >> /conf/base/etc/rc.conf ifconfig carp0 create ifconfig carp0 vhid 1 pass freenashast 192.168.137.30/24 # enable HAST daemon hastd_enable="YES" EOF Если в директории /boot/kerneldaemon отсутствует модуль if_carp.ko, скопируем его из системы на базе FreeBSD 8.2 или 8.3. Создадим файл конфигурации hast.conf, в котором определим /dev/raid3/gr0raid3 в качестве синхронизируемого между узлами хранилища: Code: cat <<EOF > /conf/base/etc/hast.conf resource freenashast { on freenas1 { local /dev/raid3/gr0raid3 remote freenas2 } on freenas2 { local /dev/raid3/gr0raid3 remote freenas1 } } EOF Копируем hast.conf в директорию /etc и перезагружаем систему: Code: cp /conf/base/etc/hast.conf /etc Создаём хранилище hast: Code: hastctl create freenashast После появления устройства /dev/hast/freenashast назначаем текущему узлу роль первичной системы: Code: hastctl role primary freenashast Создаём zpool в хранилище freenashast Code: zpool create -m /mnt gr0 /dev/hast/freenashast Создаём символическую ссылку на директорию RAID3, чтобы web-интерфейс FreeNAS распознал вручную созданное хранилище: Code: ln -s /dev/hast/freenashast /dev/raid3/gr1raid3 После этого в GUI FreeNAS можно автоматически импортировать раздел gr0 и настроить совместный доступ с использованием штатного web-интерфейса. Настроим демон devd для переключения HAST из режима master в slave и наоборот в зависимости от состояния сетевого линка: Code: cat <<EOF >> /conf/base/etc/devd.conf notify 30 { match "system" "IFNET"; match "subsystem" "carp0"; match "type" "LINK_UP"; action "/usr/local/sbin/carp-hast-switch master"; }; notify 30 { match "system" "IFNET"; match "subsystem" "carp0"; match "type" "LINK_DOWN"; action "/usr/local/sbin/carp-hast-switch slave"; }; EOF Создадим скрипт hast-carp-switch, который будет выполнять переключение режимов: Code: cat <<EOF > /usr/local/sbin/carp-hast-switch #!/bin/sh resources="freenashast" zfspool="gr0" delay=3 log="local0.debug" name="carp-hast" case "$1" in master) logger -p $log -t $name "Switching to primary provider for $resources." # in order to wait for the original primary provider to change role state # otherwise, brain-split may happen sleep $delay for disk in $resources; do # ensure that this storage can be switched while $(pgrep -lf "hastd: $disk \(secondary\)" > /dev/null 2>&1 ); do sleep 1 done # Switch role for each disk hastctl role primary $disk if [ $? -ne 0 ]; then logger -p $log -t $name "Unable to change role to primary for resouce ${disk}." exit 1 fi done # Wait for the /dev/hast/* devices to appear for disk in $resources; do for I in $(jot 60); do [ -c "/dev/hast/${disk}" ] && break sleep 0.5 done if [ ! -c "/dev/hast/${disk}" ] ; then logger -p $log -t $name "GEOM provider /dev/hast/$disk did not appear." exit 1 fi done logger -p $log -t $name "Role for HAST resources switched to primary." logger -p $log -t $name "Importing ZFS pool." zpool import -f $zfspool # restart the enabled services for srv in $(sqlite3 /data/freenas-v1.db "select srv_service from services_services where srv_enable=1" \ | xargs printf "grep 'bool_.*%s' /etc/rc.conf.local\n" | sh | awk '{print $2}') do case $srv in winbindd_enable|samba_enable) /etc/local/rc.d/samba restart ;; netatalk_enable) /etc/local/rc.d/netatalk restart ;; proftpd_enable) /etc/local/rc.d/proftpd restart ;; inetd_enable) /etc/rc.d/inetd restart ;; nfs_server_enable) /etc/rc.d/nfsserver restart ;; mountd_enable) /etc/rc.d/mountd restart ;; nfsd_enable) /etc/rc.d/nfsd restart ;; rsyncd_enable) /etc/local/rc.d/rsyncd restart ;; esac done ;; slave) logger -p $log -t $name "Switching to secondary provider for $resources." # stop the running services for srv in $(sqlite3 /data/freenas-v1.db "select srv_service from services_services where srv_enable=1" \ | xargs printf "grep 'bool_.*%s' /etc/rc.conf.local\n" | sh | awk '{print $2}') do case $srv in winbindd_enable|samba_enable) /etc/local/rc.d/samba stop ;; netatalk_enable) /etc/local/rc.d/netatalk stop ;; proftpd_enable) /etc/local/rc.d/proftpd stop ;; inetd_enable) /etc/rc.d/inetd stop ;; nfs_server_enable) /etc/rc.d/nfsserver stop ;; mountd_enable) /etc/rc.d/mountd stop ;; nfsd_enable) /etc/rc.d/nfsd stop ;; rsyncd_enable) /etc/local/rc.d/rsyncd stop ;; esac done # export the zfs pool & change role to slave for disk in $resources; do zpool export -f $zfspool sleep $delay hastctl role secondary $disk 2>&1 if [ $? -ne 0 ]; then logger -p $log -t $name "Unable to switch role to secondary for resource $disk." exit 1 fi logger -p $log -t name "Role switched to secondary for resource $disk" done ;; *) logger -p $log -t $name "Usage: $0 " exit 1 ;; esac Поменяем права доступа и перезагрузим систему: Code: chmod +x /usr/local/sbin/carp-hast-switch reboot После перезагрузки вручную установим первичных режим HAST для созданного хранилища: Code: hastctl role primary freenashast Выше представленная инструкция рассчитана на создание master-узла. Для запасного slave-узла, который возьмёт на себя управление в случае сбоя первичного узла, настойка выполняется аналогично, за одним исключением - для carp0 должен быть установлен меньший приоритет, чем на master-узле: Code: ifconfig carp0 vhid 1 pass freenashast advskew 100 192.168.137.30/24 28.12.2012 http://www.opennet.ru/tips/2723_freenas_hast_storage_ha_carp_zfs.shtml http://qq929962616.72pines.com/2012/03/configure-highly-available-storage-on-freenas/