Создание отказоустойчивого хранилища на базе 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.

Перемонтируем корневой раздел для обеспечения возможности записи:

mount -uw /

Создадим массив хранения RAID3 из дисков da1, da2, da3.

graid3 label gr0raid3 da1 da2 da3

В итоге будет создано устройство /dev/raid3/gr0raid3

Включим поддержку CARP и активируем демон hastd:

   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 в
качестве синхронизируемого между узлами хранилища:

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 и перезагружаем систему:

   cp /conf/base/etc/hast.conf /etc

Создаём хранилище hast:

 hastctl create freenashast

После появления устройства /dev/hast/freenashast назначаем текущему узлу роль первичной системы:

  hastctl role primary freenashast

Создаём zpool в хранилище freenashast

  zpool create -m /mnt gr0 /dev/hast/freenashast

Создаём символическую ссылку на директорию RAID3, чтобы web-интерфейс FreeNAS
распознал вручную созданное хранилище:

ln -s /dev/hast/freenashast /dev/raid3/gr1raid3

После этого в GUI FreeNAS можно автоматически импортировать раздел gr0 и
настроить совместный доступ с использованием штатного web-интерфейса.

Настроим демон devd для переключения HAST из режима master в slave и наоборот в
зависимости от состояния сетевого линка:

  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";
   };
</span> 
<span style="color: #461b7e;">   notify 30 {
        match "system" "IFNET";
        match "subsystem" "carp0";
        match "type" "LINK_DOWN";
        action "/usr/local/sbin/carp-hast-switch slave";
   };
   EOF

Создадим скрипт hast-carp-switch, который будет выполнять переключение режимов:

  cat &lt;&lt;EOF &gt; /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\)" &gt; /dev/null 2&gt;&amp;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}" ] &amp;&amp; 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 &amp; change role to slave
                for disk in $resources; do
                        zpool export -f $zfspool
                        sleep $delay
                        hastctl role secondary $disk 2&gt;&amp;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

Поменяем права доступа и перезагрузим систему:

   chmod +x /usr/local/sbin/carp-hast-switch
   reboot

После перезагрузки вручную установим первичный режим HAST для созданного хранилища:

   hastctl role primary freenashast

Выше представленная инструкция рассчитана на создание master-узла. Для
запасного slave-узла, который возьмёт на себя управление в случае сбоя
первичного узла, настойка выполняется аналогично, за одним исключением - для
интерфейса carp0 должен быть установлен меньший приоритет, чем на master-узле:

ifconfig carp0 vhid 1 pass freenashast advskew 100 192.168.137.30/24

Добавить комментарий