Экономные дифференциальные бэкапы с hard links

Часто возникает задача делать backup больших объемов редко изменяющихся файлов. Обычно для этого используют замечательную утилиту rsync, которая синхронизирует обновленные файлы, чем существенно экономит время бэкапа и сетевой траффик. Количество копий бэкапа, на которые происходит синхронизация, произвольно и чем оно больше — тем лучше. Естественное ограничение — свободное местом носителя. И здесь на помощь приходят две полезные опции рсинка:

--compare-dest=DIR also compare received files relative to DIR
--link-dest=DIR hardlink to files in DIR when unchanged

Первая из них создает чисто дифференциальный бэкап сравнением с существующим, то есть помещает в новый бэкап только изменившиеся файлы. Вторая — создает полный бэкап, при этом не изменившиеся файлы с помощью hardlinks ссылаются на забэкапленные. В плане использования свободного места бэкапного сервера различия несущественны, но чисто дифференциальный для использования требует наличия директории сравнения. Основанный на hardlinks — можно сразу использовать "как есть", что намного удобнее. Поэтому, будем рассматривать вариант именно с жесткими ссылками.

Логика бэкапов сделаем наподобие logrotate. Новая директория добавляется с номером 0, при этом существующие сдвигаются на +1 вперед. Количество бэкапов ограничим: последняя директория будет удаляться. Получаем следующий скрипт:

#!/bin/sh

servname="mailserv"

backup_dir=/backup/$servname/vmail
len=60

tmpname=--temp--

curr_dir="$backup_dir/$tmpname"
zero_dir="$backup_dir/`printf "%02d" 0`"
prev_dir="$backup_dir/`printf "%02d" 1`"

last_dir="$backup_dir/`printf "%02d" $len`"

date=`date`
echo "Starting backup: $date."

if [ -d "$zero_dir" ]; then
	echo "Rotating directories up to $len."

	# removing last directory
	if [ -d "$last_dir" ]; then
		rm -rf "$last_dir"
	fi

	# rotating
	for i in $(seq  $len -1 0); do
		src="$backup_dir/`printf "%02d" $i`"
		if [ -d "$src" ]; then
			mv "$src" "$backup_dir/`printf "%02d" $(($i+1))`"
		fi
	done
fi

if [ -d "$curr_dir" ] ; then
	echo "Warning: \"$curr_dir\" already exists. Probably it was not renamed during last run. Resuming it."
fi


if [ -d "$prev_dir" ] ; then
	echo "Making hard-linked incremental backup."
	rsync -rtzKL --delete --stats --link-dest="$prev_dir" -v $servname:/var/vmail "$curr_dir"
#	rsync -rtzKL --delete --stats --compare-dest="$prev_dir" $servname:/var/vmail "$curr_dir"
else
	echo "Making init backup."
	#rsync -rtzKL -e "ssh -i /home/bu/.ssh/id_dsa" --delete --stats $servname:/var/vmail "$curr_dir"
	rsync -rtzKL --delete --stats $servname:/var/vmail "$curr_dir"
fi

# moving temporary to latest
mv "$curr_dir" "$zero_dir"

echo "Backup finished: $date."
echo "================================="
echo ""

В результате на файловой системе с поддержкой жестких ссылок можно разместить бэкапов размером на порядки больше, чем размер самого носителя. Например бэкап почтового сервера размером ~870 Gb состоящий из 30 копий занимает всего 970 Gb.

PS: Для систем с разделением прав доступа и разными пользователями такой бэкап желательно делать с опцией --numeric-ids, которая сохранит (цифровые) owner:group.

One Reply to “Экономные дифференциальные бэкапы с hard links”

  1. Марат

    Все бы хорошо, но —numeric-ids требует рутовых прав.

    Reply

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

Ваш e-mail не будет опубликован.