Инкрементальный бэкап

Итак, перед нами стоит задача, сбэкапить наш сервер, и не просто сбэкапить, а сделать полный бэкап, и каждый день делать из него разностные бэкапы.

В общем случае, чтобы сделать бэкап любого типа, надо выполнить следующую команду на каждой файловой системе (к примеру, если у нас /var — это отдельная точка монтирования, значит /var надо бэкапить отдельно):

/bin/tar —create —ignore-failed-read —one-file-system —preserve-permissions —recursion —preserve-order —sparse —totals —wildcards —verbose —gzip —file=файл_бэкапа —listed-incremental=файл_метаданных —exclude-from=файл_исключений путь_который_бэкапим

Вкратце опишу, что значит каждый из параметров в данной строке.

1. /bin/tar — собственно, путь к нашему архиватору, если у вас архиватор в другом месте — укажите правильный путь.
2. —create — говорит, что мы создаем архив.
3. —ignore-failed-read — игнорируем файлы, которые не удалось прочитать, вместо останова с ошибкой — бэкап обычно идет автоматически, и лишние сбои бэкапа нам ни к чему.
4. —one-file-system — запрещает бэкапу выходить за пределы файловой системы. Вы спросите, почему бы нам не убрать эту опцию, и не бэкапить все целиком, указав в качестве пути корень (/). Да потому, что в этом случае в бэкап попадет все содержимое системных файловых систем — /dev /proc /sys, и т.д., чего нам в принципе не нужно, и что может послужить поводом для лишних ошибок в процессе развертывания архива. Не-корневые файловые системы со вложенными файловыми системами вы можете смело бэкапить рекурсивно и целиком, убирая этот параметр, но корневую файловую систему без грамотного создания списка исключений так бэкапить нельзя.
5. —preserve-permissions — эта опция говорит архиватору, что мы хотим сохранить все разрешения сохраняемых файлов.
6. —recursion — мы выполняем бэкап всех файлов и каталогов по указанному пути, а также всех файлов и каталогов всех подкаталогов.
7. —preserve-order — при бэкапе мы сохраняем порядок файлов в каталогах, чтобы после восстановления иметь более-менее точные копии и самих каталогов тоже.
8. —sparse — файлы с наличием «пустот» сохраняем именно с указанием мест и длин пустот, а не как файлы с огромным набором нулей.
9. —totals — в конце процесса выводим информацию о том, сколько данных мы сохранили.
10. —wildcards — разрешаем использовать маски (* и ?) в списке исключений — см. ниже.
11. —verbose — вывод подробной информации о процессе. Если вы не ведете лог, или вас не привлекает перспектива видеть весь список сохраняемых файлов на экране — уберите данный параметр.
12. —gzip — сжимаем архив с помощью GZIP. Если не нужно — уберите. —bzip2 не рекомендую, на практике он не дал выигрыша более 10% при сжатии разнородных данных, а вот потери во времени составили около 80%. Однако, если в сжимаемой файловой системе полно текстовых файлов — логи, например — можете попробовать, на тексте он дает ощутимое преимущество.
13. —file=файл_бэкапа — этот параметр указывает путь к создаваемому файлу бэкапа. Убедитесь, что сам этот путь не попадет в бэкап — а лучше — добавьте путь к файлам бэкапа в список исключений.
14. —listed-incremental=файл_метаданных — этот файл управляет говорит, что мы создаем именно бэкап, и управляет уровнем нашего бэкапа. Подробнее смотрите ниже.
15. —exclude-from=файл_исключений — этот файл содержит список исключений — файлов и каталогов, которые не попадут в бэкап. Пути указываются относительно основного пути бэкапа, без начального слеша. Т.е. если мы бэкапим корень (/) и хотим исключить всю папку /backup — пишем просто backup. Допускаются маски, причем на любых уровнях. Допустим, мы бэкапим каталог /www, в котором находятся подкаталоги пользователей, в которых находятся подкаталоги logs, файлы из которых мы не хотим включать в бэкап. Дописываем в файл исключений строчку */logs/*. Вуаля, сами каталоги вида пользователь/logs в бэкап попадают, а вот файлы из них, и подкаталоги — нет.
16. путь_который_бэкапим — это корневой путь, который мы бэкапим. Если бэкапим каталог /www — так и указываем: /www.

Ну вот, параметры разобрали. А теперь к самому интересному. К инкрементальности. Напоминаю про параметр —listed-incremental=файл_метаданных.

Суть в следующем:

1. Если указанного файла не существует — выполняется полный бэкап, а сам файл — создается и заполняется.
2. Если указанный файл существует — выполняется инкрементальный бэкап от момента, определяемого файлом, а сам файл — обновляется.

Итак, мы хотим сделать полный бэкап в понедельник, во вторник — инкрементальный бэкап от состояния понедельника, в среду — от вторника, и т.д. Для этого нам надо:

1. В понедельник бэкапим данные с параметром —listed-incremental=/backup/meta/monday0. При этом файла /backup/meta/monday0 существовать не должно.
2. Во вторник копируем (с заменой) файл /backup/meta/monday0 в файл /backup/meta/tuesday. Затем бэкапим данные с параметром —listed-incremental=/backup/meta/tuesday. Вуаля, мы имеем архив, представляющий собой разность данных между состоянием на момент нашего бэкапа во вторник, и состоянием на момент бэкапа на понедельник.
3. В среду копируем файл /backup/meta/tuesday в файл /backup/meta/wednesday. Затем бэкапим данные с параметром —listed-incremental=/backup/meta/wednesday.
4. И так далее.

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

Чтобы развернуть такой бэкап, допустим, на четверг — нам потребуется развернуть полный бэкап на понедельник, затем — бэкап на вторник, затем — бэкап на среду, и наконец — на четверг. Как разворачивать — читайте в конце статьи.

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

Развернуть такой бэкап можно будет в два этапа — сначала файл полного бэкапа на понедельник, а потом — файл бэкапа на нужный нам день. Куда проще, чем в прошлом случае, но и объем данных возрастает.

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

Итак, решение. Каждый месяц делаем полный бэкап с файлом метаданных month, которого не существует. Каждую неделю в понедельник копируем (с заменой) файл month в файл monday, и делаем недельный бэкап с указанием этого файла. Каждые вторник-воскресенье копируем файл предыдущего дня (во вторник — monday) в файл текущего дня, и выполняем бэкап с указанием этого файла. Собственно, и все.

Получилось?

Развернуть такой бэкап тоже несложно. Сначала разворачиваем полный (ежемесячный) бэкап на нужный месяц. Потом — недельный бэкап на нужную неделю в этом месяце. А потом — по очереди все дни до нужного нам включительно. Вот и все.

Вы скажете — архиватор сохраняет только имеющиеся файлы. А что делать, если файл удалился? Как раз для этого и придуманы файлы метаданных и команда —listed-incremental. При сохранении бэкапа в файл архива добавляется список изменившихся (в том числе и удаленных) файлов. И при развертывании следующего уровня бэкапа все файлы, удалившиеся на его момент, также будут удалены из файловой системы. Поэтому при развертывании бэкапов будьте осторожны, и не развертывайте бэкапы поверх уже имеющихся данных, взятых не из бэкапа предыдущего уровня.

Итак, с процессом бэкапа мы разобрались. Теперь я обещал рассказать вам, как разворачивать созданные бэкапы. При развертывании надо не забыть передать архиватору набор параметров, подобный тому, что мы указывали при архивации. Команда развертывания выглядит следующим образом.

/bin/tar —extract —ignore-failed-read —preserve-permissions —listed-incremental=/dev/null —recursion —preserve-order —sparse —verbose —gzip —file=файл_бэкапа —directory=путь_для_развертывания

Так же вкратце опишу, что значит каждый из параметров в данной строке.

1. /bin/tar — собственно, путь к нашему архиватору, если у вас архиватор в другом месте — укажите правильный путь.
2. —extract — говорит о том, что мы разворачиваем архив.
3. —ignore-failed-read — игнорируем файлы, которые не удалось прочитать, вместо останова развертывания с ошибкой — даже если что-то не развернулось (бывают файлы хитрого типа — например файлы устройств, которые на целевой системе могут и не развернуться), сбои нам ни к чему, проще почитать лог.
4. —preserve-permissions — эта опция говорит архиватору, что мы хотим восстановить все разрешения восстанавливаемых файлов.
5. —listed-incremental=/dev/null — заметьте, как изменился параметр. При восстановлении файл метаданных роли не играет, однако имя файла все равно требуется. Поэтому мы указываем /dev/null, на функциональность это не повлияет. Указывать —listed-incremental необходимо, поскольку при этом не только восстанавливаются заархивированные файлы и каталоги, но и удаляются занесенные в бэкап удаленные файлы и каталоги (об этом я писал выше).
6. —recursion — мы выполняем развертывание всех файлов и каталогов, а также всех файлов и каталогов всех подкаталогов.
7. —preserve-order — при восстановлении мы сохраняем порядок файлов в каталогах.
8. —sparse — файлы с наличием «пустот» восстанавливаем именно в первозданном виде, а не как файлы с огромным набором нулей.
9. —verbose — вывод подробной информации о процессе. Если вы не ведете лог, или вас не привлекает перспектива видеть весь список восстанавливаемых файлов на экране — уберите данный параметр.
10. —gzip — если архив был сжат с помощью GZIP, не забудьте про этот параметр.
11. —file=файл_бэкапа — этот параметр указывает путь к развертываемому файлу бэкапа.
12. —directory=путь_для_развертывания — путь, куда восстанавливаются файлы. Здесь зарыт небольшой подводный камень. Допустим, мы бэкапили каталог /www/users. Можно предположить, что при восстановлении надо указать тоже /www/users. А вот и нет. Дело в том, что в бэкапе сохраняются полные пути без лидирующего слеша (/). Т.е. все пути сохранились, как www/users/*. Поэтому если мы укажем здесь /www/users — все развернется, как /www/users/www/users. В нашем случае достаточно просто указать /, или использовать опцию —strip-components=N для исключения N начальных элементов пути.

Опубликовано в Backup

Рубрики