пятница, 18 ноября 2011 г.

Синхронизация датасетов с помощью инкриментальных снапшотов ZFS

Появился повод написать продолжение к предыдущей статье на эту тему. Итак, возникла задача поддерживать 2 датасета на разный хостах в состоянии максимально возможной идентичности. А именно, была использована возможность передачи инкримента двух снапшотов.

Вначале был передан полный снапшот объемом около террабайта с помощью mbuffer, как это было описано в предыдущей статье. Также предоставлены соответствующие права пользователю и прописаны rsa-ключи. Процесс занял примерно 4 часа по гигабитному каналу.
Дальше в планировщик добавляем вот такой скрипт:
#!/usr/bin/bash

#=== Options ==============
zfs_pool=zshare
zfs_dataset=dataset
lockfile="/var/run/zfs_operation.lock"
zsnapname=auto_$(date +%y%m%d%H%M)
mail_recipients="admin@example.com"
RHOST=192.168.0.1
RUSER=snapuser
#==========================

function check_result {
        last_comm_res=$?
        if [[ "${last_comm_res}" -ne 0 ]]
        then
                echo "Script: an error occurred"
                cat /var/log/tones_backup.log|mailx -s "${HOSTNAME}:Pool backup error" ${mail_recipients}
                exit ${last_comm_res}
        fi

}

if [ -f ${lockfile} ]
then
        echo "Previous runjob does not complitted successfully"
        exit 1
fi

touch ${lockfile}

if [[ ! -z $(ps -ef|grep zfs|grep send|grep ${zfs_pool}) ]]
then
        echo "Sending data from pool ${zfs_pool} detected! Try again later!"
        exit 1
fi

rlast_snapshot=$(ssh ${RUSER}@${RHOST} "/usr/sbin/zfs list -o name -r ${zfs_pool}/${zfs_dataset}|tail -1"|awk -F@ '{print $2}')
zfs list -o name ${zfs_pool}/${zfs_dataset}@${rlast_snapshot} ; check_result

zfs snapshot ${zfs_pool}/${zfs_dataset}@${zsnapname} ; check_result

zfs send -i ${zfs_pool}/${zfs_dataset}@${rlast_snapshot} ${zfs_pool}/${zfs_dataset}@${zsnapname} | ssh ${RUSER}@${RHOST} "/usr/sbin/zfs recv -F ${zfs_pool}/${zfs_dataset}"
check_result

rm ${lockfile}

Частоту вызова данного скрипта следует выбирать исходя из следующих факторов:
  • Скорость роста снапшотов
  • Ширина канала между хостами
  • Нагрузка на активном пуле
Ориентировочно: двухгигобайтный инкримент у меня передался примерно за 12 минут по гигабитному каналу. Причем узким местом была не сеть. Скорее всего это была реализация инкриментации в самом zfs, глубоко не копал.
Так же на приемнике следует подчищять старые снапшоты, чтобы их число не росло бесконечно, что быстро приведет к исчерпанию свободных блоков. Но при этом требуется оставлять как минимум последний снимок, чтобы иметь возможность накатить следующий инкримент.
#!/usr/bin/bash

#=== Options ==============
zfs_pool=zshare
zfs_dataset=dataset 
#=========================
nsnap=$(zfs list -o name -r ${zfs_pool}/${zfs_dataset}|egrep "@auto_1[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"|wc -l)
if [[ ${nsnap} -gt 3 ]]
then
      let "nsnap_destroy = $nsnap - 2"
      snap_destroy_list=$(zfs list -o name -r ${zfs_pool}/${zfs_dataset}|egrep "@auto_[0-9]10"|head -n ${nsnap_destroy})
      for dsnap in ${snap_destroy_list}
      do
              zfs destroy ${dsnap}
      done
fi

Комментариев нет:

Отправить комментарий