(… Или как мы сэкономили 600 долларов в месяц и получили лучшее решение для резервного копирования)

В Gitter, небольшом стартапе, мы каждый день усердно работаем, чтобы обеспечить лучший чат для сообществ (вы проверяли Ping Pong Wars?), Сохраняя при этом низкие затраты. Поэтому, когда я обнаружил, что мы платим 600 долларов каждый месяц за базовую услугу резервного копирования для наших баз данных вместо кубиков Рубика и крафтового пива, я подумал, что есть место для легкой победы.

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

В Gitter мы используем MongoDB на инстансах EC2 с томами EBS для хранения наших наборов данных. Это решение очень удобно, когда речь идет об архитектуре внутренней системы резервного копирования, которая поддерживает восстановление на определенный момент времени, и оно на удивление проще, чем может показаться. Я покажу вам, как мы это делаем.

Снимок

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

Вы хотите хранить и файлы данных, и журнал на одном томе EBS: в большинстве случаев это не влияет на производительность ввода-вывода, и в противном случае добиться согласованности может быть сложно.

Затем вам нужно сделать снимок тома EBS. Для этого вы можете использовать свой любимый интерфейс AWS. Помните, что создание моментального снимка - это мгновенная операция: как только AWS получит вызов api, том будет «сфотографирован» в его текущем состоянии, чтобы вы могли безопасно возобновить операции записи. Тем не менее, рекомендуется выполнить эту операцию на вторичном узле.

Преимущество создания снимков состояния EBS заключается в том, что AWS сжимает блоки и сохраняет только дифференциалы в S3, что дает дополнительную экономию с точки зрения затрат.

Вся «заморозка монго»; моментальный снимок; разморозить монго »занимает у нас около 1,4 секунды, так что это доступный компромисс, учитывая большое удобство, которое оно дает нам. Кроме того, преимуществом решения для моментальных снимков EBS является то, что AWS сжимает блоки и сохраняет только разницы в S3, что представляет собой дополнительную экономию с точки зрения затрат.

Работа сделана, вы герой, который экономит деньги! Закройте все эти дорогие счета и потратитесь на повышение зарплаты. Но достаточно ли этого?

Восстановление

Моментальные снимки EBS для вашего набора данных MongoDB могут быть детализированы только до той частоты, с которой вы их делаете, скажем, каждые 30 минут или даже один час. Этого может быть недостаточно, и делать снимок каждую минуту может быть излишним (и у вас все равно будет минутная детализация). Как ни крути, некоторые данные будут потеряны, даже если их совсем немного. Чтобы избежать этого, вы можете использовать журнал операций MongoDB для воспроизведения транзакций от момента моментального снимка до мошеннического и заполнить временной промежуток. Обратите внимание, что это работает только в том случае, если ваше окно oplog достаточно широкое, поэтому будьте очень осторожны при выборе размера вашего oplog. Вы можете следить за этим, используя этот statsd emitter.

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

Так откуда взять oplog? Вторичный узел опять же, как правило, хороший выбор. Вы можете сбрасывать журнал операций с помощью mongodump, но есть предостережение: вы хотите сбрасывать только те транзакции, которые произошли после последней в снимке, который вы восстанавливаете. Причина в том, что, например, повторное воспроизведение вставок при наличии ограничения уникальности индекса приведет к сбою восстановления. Итак, вы хотите обрезать свой журнал операций с обеих сторон: после снимка и до катастрофического события.

Для этого вам нужно найти метку времени последней транзакции в снимке. Создайте том EBS, используя моментальный снимок, сделанный до катастрофического события, и смонтируйте его на экземпляре. Запустите привязку mongod к localhost и временному порту, скажем, 27272. Затем выполните этот запрос:

$ mongo —-port 27272 local
> db.oplog.rs.find({}, {ts: 1,}).sort({ts: -1}).limit(1)
{"ts" : Timestamp(1459850401, 11)}

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

$ mongodump -h sendondary-node \
--db local \
--collection oplog.rs \
--out oplog \
--query '{"ts": { "$gt": { "$timestamp": {"t": 1459850401, "i": 11}}}}'

Преобразуйте данные bson в json, чтобы они стали доступны для чтения людям:

$ bsondump oplog/local/oplog.rs.bson > oplog.json

Найдите метку времени фиктивной транзакции, которая представляет момент, пока вы не захотите воспроизвести журнал операций:

$ grep "Hello. My name is Inigo Montoya. You killed my father. Prepare to die." oplog.json
{"ts":{"$timestamp":{"t":1459852199,"i":1}},"h":{"$numberLong":"-6882763316726998947"},"v":2,"op":"i","ns":"quotes.movies","o":{"_id":{"$oid":"570393abf5d634897f2360a3"},"quote":"Hello. My name is Inigo Montoya. You killed my father. Prepare to die.","character":"Inigo Montoya","title":"The Princess Bride"}

В этом случае ваша временная метка 1459852199: 1.

Затем переместите oplog туда, где его будет искать mongorestore:

mv oplog/local/oplog.rs.bson oplog/oplog.bson

Теперь вы готовы воспроизвести oplog, используя - oplogLimit для установки разделителя:

$ mongorestore -h localhost:27272 --oplogReplay --oplogLimit 1459852199:1 oplog

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

Теперь вы готовы перезапустить экземпляр в производственной среде. Отличная работа!

Этот пост написал Даниэле Валериани.