Резервное копирование MongoDB

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

One thought on “Резервное копирование MongoDB

Добавить комментарий для Андрей Отменить ответ

Ваш e-mail не будет опубликован.

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>