В далекие времена довелось поработать с такими комбайнами как система резервного копирования Bacula и Amanda. Однако в системах построенных изначально на высокой доступности (HighAvailability) их применение не совсем оправдано. Причина — большая часть конфигурации хранится в GIT/SVN, каждый узел системы настраивается через puppet, chef или cfengine. Таким образом в случае выхода из строя одного сервера это никак не сказывается на работе комплекса. А систему легко восстановить путем применения написанных манифестов.
Таким образом на первый план вышел более простой в использовании rsnapshot. Бесспорно, основной конек его использование в связке с rsync, однако его можно смело применять для резервного копирования базы данных. Самое простое, что приходит в голову резервная копия PostgreSQL
backup_script /usr/bin/ssh root@postgresql-hostname "su -l postgres -c pg_dumpall | gzip" > dump.sql.gz postgresql-hostname/postgres/
Важно! При копировании примера директивы разделяются табуляцией.
Сложность приключилась при появлении в парке MongoDB. Дело в том, что штатная mongodump
создает резервные копии всей базы в отдельной директории, таким образом простым способом аналогичный подход не применим. Существует вариант создания резервной копии через backup_script
и последующий его трансфер директивной backup
. Стремясь к идеальному мы не могли себе позволить столь прямолинейное решение 🙂 На помощь, как обычно, пришла командная оболочка и на выходе родилась следующая конструкция
backup_script /usr/bin/ssh root@mongodb-hostname 'cd /var/tmp && tmpdir=$(mktemp -d mongodump.XXXXXX) && trap "{ rm -fr $tmpdir; }" EXIT TERM INT && mongodump -o $tmpdir --oplog > /dev/null && tar czf - $tmpdir' > mongodump.tar.gz mongodb-hostname/mongo/
Важно! При копировании примера директивы разделяются табуляцией.
Если разложить этот пример по строчкам получим
cd /var/tmp && tmpdir=$(mktemp -d mongodump.XXXXXX) && trap "{ rm -fr $tmpdir; }" EXIT TERM INT && mongodump -o $tmpdir --oplog > /dev/null && tar czf - $tmpdir
Второй строчкой мы создаем временную директорию, в которую будем в строке четыре производить сохранение в формате bson резервной копии всех баз MongoDB и oplog
. Изначально была использована более сокращенная конструкция, заменяющая две первые строчки
tmpdir=$(mktemp -d /var/tmpmongodump.XXXXXX)
Минус ее заключается в том, что на последнем шаге при получении TAR архива мы на STDERR получаем сообщение
tar: Removing leading `/' from member names
Направлять STDERR в /dev/null
не наш путь. Поэтому изначально мы переходим во временную директорию /var/tmp
. Вывод STDOUT у mongodump
завязан на /dev/null
, так как в процессе работы скрипт выводит не нужную отладочную информацию. Здесь должен идти плевок в сторону разработчиков MongoDB, которые нарушают основные парадигмы unixway. Более того не предусмотрели ключ --quiet
.
Самой интересной комбинацией и ради чего все это затевалось является строчка
trap "{ rm -fr $tmpdir; }" EXIT TERM INT
Которая при завершении выполнения всех процессов (в нашем случае при успешной передаче TAR архива на принимающую сторону) или при нажатии Ctrl+C
произведет удаление временной директории.
Важно отметить, что в нашем случае резервная копия снимается на отдельный раздел. Физически хранилище MongoDB находится на другом дисковом RAID массиве, таким образом дисковые активности не пересекаются. Есть небольшой минус связанный с вымыванием дискового кеша. Так как резервная копия снимается ночью на производительности это не отражается.
Указанный скрипт легко адаптируется к ситуации, когда копия изначально снимается в директорию на резервном сервере (в помощь ключ --host
для mongodump
), архивируется и производится зачистка временных файлов. Однако это задачка для наших читателей.