Скрипт резервного копирования через rsync

Возникла необходимость как-то и куда-то бэкапится. Причём чтобы процессоры не грузились и место не занималось, а бэкапы ротэйтились. Раньше всегда пользовался fsbackup, но захотелось отказаться от архивирования. Для решения задачи была использована rsync и механизм жёстких ссылок (так называемых хардлинков) файловой системы.

Архитектура: есть отдельно стоящий сервер с большим винтом — на нём и работает скрипт. Есть много разных серверов с доступом по ssh, на которых в ~/.ssh/authorized_keys добавлен публичный ключ пользователя, под которым работает скрипт резервного копирования.

Логика работы: в определённое время скрипт по ssh синхронизирует содержимое резервируемой папки с папкой домен/latest, а потом копирует её в папку с сегодняшней датой, создавая при этом жёсткие ссылки на файлы, затем удаляет папки со старыми датами. Т.к. синхронизируется только сожержимое каталога, дампить базу по крону нужно на клиентской машине перед тем, как rsync заберёт файлы.

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

#!/bin/sh
# simple rsync backup script written by farmal.in 2011-01-21
#
# latest backup is always in $SDIR/domains/$domain/latest folder
# all backups which are older than 7 days would be deleted
# backup.ini file can't contain comments, empty lines and spaces in domain names
#
# example of a GOOD backup.ini:
# mydomain.com user@mydomain.com:/path/to/public_html
#
 
SDIR="/usr/local/backup"
SKEY="$SDIR/.ssh/id_rsa"
SLOG="$SDIR/backup.log"
PID_FILE="$SDIR/backup.pid"
ADMIN_EMAIL="email@domain.com"
 
 
if [ -e $PID_FILE ]; then
        echo "this task is already running or previous run was completed with errors on `hostname`" | mail -s "Some mess with backups on `hostname`..." $ADMIN_EMAIL
        exit
fi
 
touch $PID_FILE
 
# redirecting all output to logfile
exec >> $SLOG 2>&1
 
# parsing backup.ini file into $domain and $from variables
cat backup.ini | while read domain from ; do
	destination="$SDIR/domains/$domain"
	# downloading a fresh copy in 'latest' directory
	echo -e "`date` *** $domain backup started">>$SLOG
 
	# start counting rsync worktime
	start=$(date +%s)
	rsync --archive --one-file-system --delete -e "ssh -i $SKEY" "$from" "$destination/latest" || (echo -e "Error when rsyncing $domain. \n\n For more information see $SLOG:\n\n `tail $SLOG`" | mail -s "rsync error" $ADMIN_EMAIL & continue)
	finish=$(date +%s)
	echo -e "`date` *** RSYNC worked for $((finish - start)) seconds">>$SLOG
 
    # cloning the fresh copy by hardlinking
	cp --archive --link "$destination/latest" "$destination/`date +%F`"
	# deleting all previous copies which are older than 7 days by creation date, but not 'latest'
	find "$destination" -maxdepth 1 -ctime +7 -type d -path "$destination/????-??-??" -exec rm -r -f {} \;
	echo "`date` *** The size of $domain/latest is now `du -sh $destination/latest | awk '{print $1}'` ">>$SLOG
	echo -e "`date` *** $domain backup ended">>$SLOG
	echo -e "`date` *** Total allocated `du -sh $destination | awk '{print $1}'`">>$SLOG
	echo -e "------------------------------------------------------------------">>$SLOG
done
 
rm $PID_FILE

6 thoughts on “Скрипт резервного копирования через rsync

  1. schlag

    Прочитал сталью на хабре.
    Но аккаунта там не имею, поэтому оставляю комментарий здесь.

    Не первый раз вижу подобную реализацию бэкапа и все время думаю: какой смысл в “как бы снэпшетах” реализованных хардлинками? Сама идея таких “снэпшетов” порочна. Они сохраняют состояние поддерева файловой системы на момент резервного копирования только в части касающейся наличия/отсутствия того или иного элемента ФС (файла/каталога), но никак не содержания этих элементов. Это объясняется тем, что при следующей сессии резервного копирования rsync обновит содержание файлов в каталоге latest, а значит обновятся и все файлы в каталогах `date +%F` т.к. и в каталоге latest и в каталогах `date +%F` хардлинки ссылаются на одни и те же inode!

    Значит, если бэкапы делаются каждый день, при логическом повреждении какого-либо файла N-ого числа, в N+1 день мы уже не сможем восстановить поврежденный файл на состояние N-1 числа.

    Т.о. пользы от псевдоснэпшетов – ноль!

    Другое дело, если на сервере резервного копирования использовать честные снэпшеты средствами ФС (например, zfs): будем иметь и статичные во времени копии, и экономию пространства диска (т.к. zfs будет дописывать только изменившиеся/новые блоки файлов).

    Reply
    1. anonymous Post author

      я тоже через некоторое время после написания скрипта спохватился и про это подумал :) но вскрытие показало что файловая система создаёт новый узел, при попытке изменить тот, на который ссылаются из разных мест (происходит так называемы дитач). подробнее тут
      http://habrahabr.ru/blogs/sysadm/128617/#comment_4279281

      Reply
    2. anonymous Post author

      что касается снэпшотов системы – это оптимальный вариант для бэкапов в пределах одной файловой системы, но скрипт написан для использования на удалённых серверах.

      Reply
  2. samnick

    ну как говориться – нет предела совершенству

    погоняю недельку другую а там займусь “доведением до совершенства на свой лад ” о результатах отпишусь

    Reply
    1. anonymous Post author

      буду признателен, если выложите доработанную версию

      Reply
  3. Pingback: Скрипт резервного копирования через rsync | Unix-системы

Leave a Reply to samnick Cancel reply

Your email address will not be published. Required fields are marked *