Создание инкрементальных и дифференциальных архивов при помощи tar в Linux

  • Автор:

tar-incremental-backup-000.pngИнкрементальные и дифференциальные архивы широко используются при резервном копировании, позволяя достичь компромисса между нужной частотой создания копий, глубиной архива и занимаемым копиями местом на устройствах хранения. Несмотря на то, что Linux есть специализированные пакеты для резервного копирования, их использование во многих случаях будет избыточным, потому что такая задача достаточно просто решается при помощи архиватора tar, который присутствует "из коробки" в любом дистрибутиве.

Возможности tar

Утилита tar является штатным архиватором в Unix-подобных системах и полностью соответствует философии Unix - делать только одну вещь, но делать ее хорошо. Многие, возможно, удивятся, но tar не умеет сжимать архивы, потому что архивация данных и их сжатие - это разные операции. Архивация предусматривает помещение файлов в единый контейнер, целостность которого легко контролировать, особенно при передаче по каналам связи. Сжатие - это дополнительная операция, выполняемая над архивом, которая позволяет уменьшить его размер, но не является обязательной.

В современном понимании "архивация" и "сжатие" чаще всего являются синонимами, так как архивация без сжатия практически никогда не используется. Поэтому tar умеет создавать сжатые архивы используя установленные в системе утилиты сжатия, обычно по умолчанию это gzip и bzip, но никто не мешает использовать вам практически любые алгоритмы. Более подробно консольные утилиты для сжатия мы рассматривали в нашем тестировании.

Как и многие утилиты командной строки tar имеет два варианта записи опций: полную и краткую. Краткая удобна при интерактивной работе в консоли, зато полная более наглядна и удобочитаема. Сравните:

tar -czf archive.tgz ~/my_folder

или

tar --create --gzip --file=archive.tgz ~/my_folder

Даже не будучи знакомым с опциями утилиты вполне можно понять, что мы создаем архив папки my_folder, сжимаем его при помощи gzip и помещаем в файл archive.tgz. При краткой записи все далеко не так очевидно. Поэтому в скриптах мы советуем использовать полный синтаксис, что позволит быстро разобраться в них вам и вашим коллегам, особенно если вы используете редкие опции.

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

Создать такой архив можно командой:

tar --create --gzip --file=archive.tgz  --listed-incremental=my_folder.snar ~/my_folder

К стандартной команде добавилась новая опция --listed-incremental, которая указывает на файл метаданных. Если он отсутствует, то создается полная копия, иначе состояние файлов сверяется с метаданными и создается инкрементальный архив.

Также при создании резервных копий могут быть использованы опции:

  • --ignore-failed-read - игнорирует файлы, которые невозможно прочитать, например, заблокированные другими процессами или на которые нет прав.
  • --one-file-system - не выходить за пределы файловой системы, используется при нахождении в целевом каталоге точек монтирования на другие разделы.
  • -p или --preserve-permissions - восстанавливает владельца и разрешения для объектов. Используется только при извлечении.
  • -s или --preserve-order - предписывает использовать порядок файлов из архива при извлечении, может быть полезна на компьютерах с малым объемом оперативной памяти, в ином случае не имеет смысла. Используется только при извлечении.
  • --sparse - используется при архивации разреженных файлов, т.е. тех, которые имеют в своем составе незаписанные области, позволяет не копировать пустые участки файлов. Может существенно замедлить процесс архивации, так как перед архивированием файл будет дополнительно прочитан.

Практический смысл из указанных опций имеет только --ignore-failed-read, особенно если вы выполняете бэкап с правами обычного пользователя. Остальные опции следует применять исключительно при наличии такой необходимости. Скажем --preserve-permissions имеет смысл, если вы восстанавливаете архив со сложной структурой прав на объекты, например, копию веб-сайта, для обычного архива личных файлов ее использование обычно бессмысленно.

Опции --preserve-order и --sparse скорее всего не пригодятся на современных системах. Недостатка оперативной памяти сегодня не ощущается даже в бюджетном сегменте, а типичный разреженный файл - это чаще всего контейнер виртуального жесткого диска и он все равно будет сжат, что в итоге даст практически тот же эффект, только без дополнительной операции чтения большого файла.

Если нужно копировать не всё, то следует указать исключения, для этого используются две опции: --exclude и --exclude-from. Первая позволяет просто указать файл, папку или паттерн для исключения. Например:

--exclude=*.tmp

Данная запись исключает файлы с расширением tmp внутри копируемой директории.

--exclude=dir1/tmp

А такая конструкция предписывает не копировать директорию dir1/tmp. Обратите внимание, что все пути указываются относительно директории архивируемой директории, т.е. в нашем случае полный путь к папке будет ~/my_folder/dir1/tmp.

Если нужно исключить сразу несколько объектов, то опцию следует использовать нужное число раз:

--exclude=*.tmp --exclude=dir1/tmp

Это может быть неудобно, поэтому можно поместить исключаемые объекты в отдельный файл, по одной записи на строку и использовать его совместно с другой опцией:

--exclude-from=exclude.list

Составляя списки учтите, что записи обрабатываются "дословно", поэтому обращайте внимание на наличие пробелов, они не видны в редакторе, но являются самой частой причиной того, что списки не работают как надо.

Мы рассмотрели только самые часто используемые опции, для полной информации обратитесь к официальной документации.

Создание инкрементальных архивов

Инкрементальным называется архив, который содержит только новые или измененные с момента предыдущего копирования файлы.

tar-incremental-backup-001.pngК достоинствам этого типа архивов можно отнести небольшой размер и эффективное использование пространства хранилища (не дублируются данные). Но для восстановления нам потребуется последняя полная копия и все инкрементальные архивы к ней. Если один из архивов в цепочке окажется поврежден или утерян - полноценное восстановление сделать не удастся, поэтому не следует злоупотреблять большой длинной цепочки.

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

#!/bin/sh

#Указываем путь к директории с бэкапами
BACKUP=/home/andrey/backup

#Получаем номер дня недели
DAY=$(date +%u)

#Если воскресенье - удаляем файл метаданных и архивы
if [ "$DAY" = "7" ]; then
NUM="0"
rm -rf $BACKUP/example.snar
rm -rf $BACKUP/*.tgz
else
NUM="$DAY"
fi

#Создаем архив
tar --create \
--gzip \
--file=$BACKUP/example.$NUM.tgz \
--ignore-failed-read \
--listed-incremental=$BACKUP/example.snar \
/home/andrey/example

На что следует обратить внимание? Прежде всего на указание пути, в данном случае мы используем полный путь /home/andrey/backup, вместо относительного ~/backup, потому что относительный путь зависит от контекста исполнения. Так если мы запустим скрипт от имени суперпользователя, то ~/backup будет обозначать /root/backup, что может привести к самым неожиданным последствиям.

Также мы используем переносы строки, чтобы улучшить читабельность скрипта, для этих целей используется символ обратного слеша, который следует отделить пробелом от текста команды. Эта же запись в строку будет выглядеть так:

tar --create --gzip --file=$BACKUP/example.$NUM.tgz --ignore-failed-read --listed-incremental=$BACKUP/example.snar /home/andrey/example

Такой скрипт можно поместить в cron с исполнением один раз в сутки, и мы получим в папке с бэкапами архивы с номерами от 0 до 6, где 0 - будет полный архив, а 1-6 - инкрементальные к нему.

Для примера мы каждый день добавляли в папку example по одному изображению, результат работы скрипта приведен ниже:

tar-incremental-backup-002.pngКак видим, каждый архив содержит только добавленные данные и не повторяет содержимое других архивов.

Создание дифференциальных архивов

Дифференциальный архив, в отличии от инкрементального, содержит все новые или измененные данные со времени последнего полного копирования.

tar-incremental-backup-003.pngПоэтому преимуществом таких архивов является быстрое и простое восстановление - нам понадобится полный архив и последняя дифференциальная копия. Недостаток тоже очевиден - рост архива за счет повторения копируемых данных, при определенной глубине архива файл дифференциальной копии даже может превысить по размеру полный архив, все зависит от интенсивности изменения данных.

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

Вот пример такого скрипта, все условия аналогичные скрипту выше:

#!/bin/sh

#Указываем путь к директории с бэкапами
BACKUP=/home/andrey/backup

#Получаем номер дня недели
DAY=$(date +%u)

#Удаляем текущие метаданные
rm -rf $BACKUP/example.snar

#Если воскресенье - удаляем файл начальных метаданных и архивы
if [ "$DAY" = "7" ]; then
NUM="0"
rm -rf $BACKUP/example.snar0
rm -rf $BACKUP/*.tgz
else
NUM="$DAY"
fi

#Если есть начальные метаданные - копируем их
if [ -f "$BACKUP/example.snar0" ]; then
cp $BACKUP/example.snar0 $BACKUP/example.snar
fi

#Создаем архив
tar --create \
--gzip \
--file=$BACKUP/example.$NUM.tgz \
--ignore-failed-read \
--listed-incremental=$BACKUP/example.snar \
/home/andrey/example

#Если воскресенье - создаем начальную копию метаданных
if [ "$DAY" = "7" ]; then
cp $BACKUP/example.snar $BACKUP/example.snar0
fi

Логика скрипта довольно проста. В обычный день мы удаляем перед архивированием текущий файл метаданных example.snar и копируем на его место начальную копию файла example.snar0 . В итоге каждый создаваемый архив будет содержать все новые или измененные файлы начиная с воскресенья, в которое мы создали полный архив.

В воскресенье мы также удаляем файл начальных метаданных, перед этим удалив текущий файл, это заставит tar создать новый архив и новый файл метаданных, который мы дополнительно скопируем как начальную копию.

Для проверки мы снова каждый день добавляли в директорию по изображению, но результат уже оказался другим:

tar-incremental-backup-004.pngТеперь каждый последующий архив включает данные всех предыдущих, но при этом общий размер хранимых данных ощутимо выше, чем при инкрементальном копировании.

В заключение хочется отметить, что приведенные скрипты не являются готовыми решениями для создания резервных копий, а только лишь представляют примеры как можно создавать архивы того или иного типа при помощи tar.