суббота, 11 октября 2014 г.

Инкрементальный бэкап в линукс

Зачастую требуется резервное копирование большого количество данных, в которых
изменяется лишь незначительная их доля. Для этой цели подходит инкрементальный
бэкап, т.е. делается один полный бэкап, а потом записываются лишь изменения в
резервируемых данных.
Я не буду здесь рассматривать все существующие способы инкрементального
резервного копирования, приведу лишь 3, которыми я пользовался.

rdiff-backup

Самое просто решение, просто указываем две папки - откуда копировать и куда
копировать. Данная утилита определяет изменения в файловой системе и записывает
лишь их. В дальнейшем можно восстановить не только последнюю копию, но и все
копии, которые были сделаны до этого. Также при помощи rdiff-backup-fs можно
смонтировать каталог с резервной копией через fuse и получить виртаульную
файловую систему с папками, соответствующими времени копирования, в которых
будут находится файлы, скопированные в это время.
На данный момент утилита имеется в репозиториях большинства популярных
дистрибутивов, поэтому установка не должна составить трудности.

Примеры

Простое резервное копирование папки /home:
$ rdiff-backup /home/ /backup/
Резервное копирование определённых папок:
$ rdiff-backup --globbing-file-list lits.txt /home/user/ /backup/
Пример содержания файла list.txt:
+ /home/user/.asoundrc
+ /home/user/.bashrc
- /home/user/bin/netbeans-7.3.1
- /home/user/bin/eclipse
- /home/user/bin/eclipse-cpp
+ /home/user/bin
+ /home/user/Books
+ /home/user/.config
+ /home/user/databases
+ /home/user/.gconf
+ /home/user/.gconfd
+ /home/user/.local/share/gtg
+ /home/user/.local/share/gnote
+ /home/user/.local/share/Psi+
+ /home/user/.profile
+ /home/user/Projects
+ /home/user/.psi
+ /home/user/.purple
+ /home/user/list.txt
+ /home/user/scripts
+ /home/user/.Skype
+ /home/user/.ssh
+ /home/user/.vim
+ /home/user/.vimrc
+ /home/user/vimwiki
+ /home/user/Документы
+ /home/user/Рабочий стол
- **
+ означает добавить файл или директорию, - - убрать из списка резервного
копирования. В данном примере добавляем определённые каталоги, при этом из папки
bin исключаем некоторые папки, которые резервировать не нужно.
Вместо файла со списком можно использовать ключи --include, --include-regexp
и прочие, подробнее в man rdiff-backup.

Особенности

Можно выделить плюсы и минусы данного метода.
Плюсы:
  • можно получить доступ к любой версии резервируемых файлов;
  • можно удалять старые бэкапы.
Минусы:
  • резервная копия хранится в виде множества файлов, которые с каждым бэкапом
    обновляются до текущего состояния (из-за этого нет возможности дописывать
    бэкап на dvd-r, например).

Incremental tar

Архиватор tar, который содержится в любом дистрибутиве, умеет делать
инкрементальные архивы, если указать опцию -g с указанием файла снапшота.

Примеры использования

Создаём полный бэкап домашней папки:
$tar -cvjf /backup/home.tar.bz2 -g /backup/home.snapshot -C /home/user/ .
Делаем следующий бэкап (например, через неделю):
$tar -cvjf /backup/home.1.tar.bz2 -g /backup/home.snapshot -C /home/user/ .
Первая команда создаёт стандартный архив tar и снапшот состояния файловой
системы на момент бэкапа. Вторая команда читает этот снапшот и архивирует только
изменённые файлы.
Желательно, создавать свой файл снапшота для каждого архива, т.к. он каждый раз
обновляется. Это позволит делать инкрементальный бэкап не только от предыдущего,
но и от первого архива, т.е. создать дифференциальный бэкап.

Недостатки

Существует один недостаток - это то, как tar определяет, какие файлы изменились.
Он проверяет файлы по inode, сверяет атрибуты файла, если они изменились, то
добавляет файл в архив. Вроде бы всё хорошо, но некоторые файловые системы имеют
свойство менять inode файлов для оптимизации или просто не имеют таковых, а ядро
при монтировании назначает каждый раз произвольные значения. Таким образом, при
изменении inode всех файлов, получается полный бэкап. Я с этим столкнулся на
файловой системе btrfs. Также вообще не получится сделать подобное на fat.

Tar + rdiff

Это такой гибридный способ на основе предыдущих, я стал его использовать в
последнее время. Принцип состоит в следующем:
Создание первого бэкапа:
  1. Создаём полный архив tar без сжатия:
    $tar -cvf backup.tar /home
  2. Создаём файл signature с помощью rdiff:
    $rdiff signature backup.tar backup.signature
  3. Архив можно сжать для экономии места.
Создание следующих бэкапов:
  1. Создаём полный архив tar без сжатия.
  2. Создаём файл signature с помощью rdiff для этого архива, например:
    $rdiff signature backup1.tar backup1.signature
  3. Создаём файл rdiff - разницу между предыдущим и текущим архивами:
    $rdiff delta backup.signature backup1.tar backup1.rdiff
  4. Можно удалить backup1.tar
Как видно, для создания инкрементального архива не требуется наличие первой
полной копии. Как восстановить последний архив:
$rdiff patch backup.tar bakup1.rdiff backup1.tar
Если бэкапов несколько, то восстановление осуществляется по цепочке.
Сжатие архива и создание сигнатуры для первого архива, а также создание разницы
и сигнатуры для последующих архивов можно выполнить за один шаг, не создавая
несжатые файлы с полным архивом, для этого можно использовать именованные
каналы. Привожу пример скрипта для архивации (для понятности добавил
комментарии):
#!/bin/bash
prefix=all
dt=`date +%Y-%m-%d`
srcsignature="$1"
#Проверка вида бэкапа
if [ -e "$srcsignature" -a -n "$srcsignature"]
then
    ext="rdiff.xz"
else
    ext="tar.xz"
fi
sourcefile=$prefix.$ext
endfile=$prefix.$dt.$ext
sourcesignature=$prefix.signature
endsignature=$prefix.$dt.signature

#Создаём именованные каналы
mkfifo for_signature for_delta

#Создание сигнатуры
rdiff signature for_signature $sourcesignature &
if [ -e "$srcsignature" -a -n "$srcsignature"]
then
    #Создание дельты
    rdiff delta $srcsignature for_delta | xz -zc > $sourcefile &
else
    #Сжатие полного архива
    xz -zc for_delta > $sourcefile &
fi

#Архивация (исправить для использования)
tar -cvf - -C ~/ \
scripts/ \
Документы/ \
Projects/ \
vimwiki/ \
.local/share/gnote/ |\
tee for_signature for_delta > /dev/null

#На всякий случай ждём окончания действий
sleep 10
sync
#Переименовываем файлы
mv $sourcefile $endfile
mv $sourcesignature $endsignature

#Удаляем каналы
rm for_signature for_delta
В качестве единственного параметра этого скрипта выступает файл сигнатуры
предыдущего бэкапа. Если файл не существует, или запуск производился без
параметров, делается полный бэкап. Сам список задаётся в команде tar, там же
можно указать опции архивации.
Есть один недостаток - архивирование выполняется долго, т.к. по сути создаётся
полный архив, но оно того стоит, т.к. в этом случае, в отличие от
инкрементального копирования средствами tar, получаются файлы меньшего размера.
Дело в том, что rdiff находит разницу между бинарными файлами, а в случае с
архивами - между содержанием архивов. Т.е. если изменится незначительно большой
файл, то при помощи rdiff будут записаны только изменения этого файла, а при
помощи tar будет перезаписан весь файл полностью.

Итог

Всё зависит от способа хранения резервных копий, если записывать инкрементальные
архивы на dvd-r, то подойдут 2 и 3 способы, а первый подойдёт только в случае
копирования на внешний винчестер или на другой компьютер по сети.
P.S.:
Кстати, rdiff-backup, использует rdiff для хранения изменений в файлах, хотя об
этом можно догадаться и из названия.
P.P.S.:
Библиотека rdiff также используется в rsync.

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

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