Инкрементальный бэкап
Итак, перед нами стоит задача, сбэкапить наш сервер, и не просто сбэкапить, а сделать полный бэкап, и каждый день делать из него разностные бэкапы.
В общем случае, чтобы сделать бэкап любого типа, надо выполнить следующую команду на каждой файловой системе (к примеру, если у нас /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 начальных элементов пути.