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

Если вы здесь впервые, обратите внимание на приквел Self-Hosted MongoDB.

Хорошо, тогда, выбирая с того места, где мы остановились, давайте начнем с переноса данных в MongoDB.

Теперь основные шаги по переносу данных из одной MongoDB в другую:

  1. Создайте заархивированную резервную копию существующих данных
  2. Сбросить данные в новую БД

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

Создание резервной копии

Мы собираемся использовать существующую утилиту mongodump для создания резервной копии базы данных.

Запустите эту команду на исходном сервере базы данных

mongodump --host="hostname:port" \
  --username="username" --password="password" \
  --authenticationDatabase "admin" \
  --db="db name" --collection="collection name" --query='json' \
  --forceTableScan -v --gzip --out ./dump

: исходное имя хоста MongoDB вместе с портом. По умолчанию это localhost:27017. Если это строка подключения, вы можете использовать эту опцию --uri="mongodb://username:password@host1[:port1]..."

--username: указывает имя пользователя для аутентификации в базе данных MongoDB, которая использует аутентификацию.

--password: указывает пароль для аутентификации в базе данных MongoDB, которая использует аутентификацию.

--authenticationDatabase: указывает базу данных аутентификации, в которой был создан указанный --username.

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

--db: указывает базу данных, из которой необходимо создать резервную копию. Если вы не укажете базу данных, mongodump будет собирать данные из всех баз данных в этом экземпляре.

В качестве альтернативы вы также можете указать базу данных непосредственно в строке подключения URI, например mongodb://username:password@uri/dbname.
Предоставление строки подключения при одновременном использовании --db и указании противоречивой информации приведет к ошибке.

--collection: указывает коллекцию для резервного копирования. Если вы не укажете коллекцию, этот параметр копирует все коллекции в указанной базе данных или экземпляре в файлы дампа.

: Предоставляет документ JSON в качестве запроса, который дополнительно ограничивает документы, включенные в вывод mongodump.
Вы должны заключить документ запроса в одинарные кавычки('{ ... }'), чтобы гарантировать, что он не взаимодействует с вашей средой.
Запрос должен быть в расширенном формате JSON v2 (либо в расслабленном, либо в каноническом/строгом режиме), включая заключение имен полей и операторов в кавычки, например '{ "created_at": { "\$gte": ISODate(...) } }'.

Чтобы использовать параметр --query, необходимо также указать параметр --collection.

--forceTableScan: заставляет mongodump сканировать хранилище данных напрямую. Как правило, mongodump сохраняет записи по мере их появления в индексе поля _id.

Если вы укажете запрос --query, mongodump будет использовать наиболее подходящий индекс для поддержки этого запроса.
Следовательно, вы не можете использовать --forceTableScan с опцией.

: сжимает вывод. Если mongodump выводит в каталог дампа, новая функция сжимает отдельные файлы. Файлы имеют суффикс .gz.

: указывает каталог, в который mongodump будет записывать файлы для дампа баз данных. По умолчанию mongodump сохраняет выходные файлы в каталоге с именем dump в текущем рабочем каталоге.

Восстановление резервной копии

Мы будем использовать служебную программу под названием mongorestore для восстановления резервной копии базы данных.

Скопируйте дамп каталога резервной копии в новый экземпляр базы данных и выполните следующую команду:

mongorestore --uri="mongodb://user:password@host:port/?authSource=admin" \
  --drop --noIndexRestore --gzip -v ./dump

Замените учетные данные новыми учетными данными базы данных. Unline на предыдущем шаге в строке URI указана опция --authenticationDatabase.

Кроме того, используйте --gzip, если оно используется при создании резервной копии.

: перед восстановлением коллекций из дампа резервной копии удаляет коллекции из целевой базы данных. Он не удаляет коллекции, которых нет в резервной копии. --noIndexRestore: запрещает mongorestore восстанавливать и создавать индексы, как указано в соответствующем выводе mongodump.

Если вы хотите изменить имя базы данных при восстановлении, вы можете сделать это с помощью параметров
--nsFrom="old_name.*" --nsTo="new_name.*".

Однако это не сработает, если вы перейдете с oplogs, что является обязательным требованием при переносе из онлайн-экземпляра.

Единственная проблема с миграцией из онлайновой базы данных — невозможность приостановить обновления во время миграции. Итак, вот обзор шагов,

  1. Запустите начальную массовую миграцию с захватом oplogs
  2. Запустите задание синхронизации, чтобы уменьшить задержку переключения подключения к базе данных.

Теперь, чтобы получить oplogs, необходимо инициализировать набор реплик в исходной и целевой базах данных. Это связано с тем, что oplogs захватываются из пространства имен local.oplog.rs, которое создается после инициализации набора реплик.

Вы можете следовать этому руководству, чтобы настроить набор реплик.

Первоначальная миграция с Oplog Capture

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

Запустите программу mongodump со следующими параметрами:

mongodump --uri=".../?authSource=admin" \ --forceTableScan --oplog \ --gzip -v --out ./dump

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

Восстановите данные с помощью повтора оплога

Для того, чтобы переиграть оплоги, требуется особая роль. Давайте создадим и назначим роль пользователю базы данных, используемому для миграции.

Создать роль

db.createRole({
  role: "interalUseOnlyOplogRestore",
  privileges: [
    {
      resource: { anyResource: true },
      actions: [ "anyAction" ] 
    }
  ],
  roles: []
})

Назначить роль

db.grantRolesToUser(
  "admin",
  [{ role:"interalUseOnlyOplogRestore", db:"admin" }]
);

Теперь вы можете восстановить с помощью программы mongorestore со следующими параметрами,

mongorestore --uri="mongodb://admin:.../?authSource=admin" \
  --oplogReplay 
  --gzip -v ./dump

В приведенной выше команде используется тот же пользователь admin, с которым была связана роль.

--oplogReplay: после восстановления дампа базы данных воспроизводит записи oplog из файла bson и восстанавливает базу данных в резервную копию на момент времени, полученную с помощью команды mongodump --oplog.

Уменьшение задержки переключения соединения с базой данных

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

Если вы используете MongoDB версии 3.6+, лучше использовать подход Change Stream, который представляет собой основанный на событиях механизм, введенный для оптимизированного сбора изменений в вашей базе данных. Вот статья, посвященная этому https://www.mongodb.com/blog/post/an-introduction-to-change-streams

Ознакомьтесь с общим сценарием синхронизации, который вы можете запускать как задание CRON каждую минуту.

Обновите переменные в этом скрипте и запустите как

$ ./delta-sync.sh from_epoch_in_milliseconds

# from_epoch_in_milliseconds is automatically picked with every iteration if not supplied

Или вы можете настроить задание cron для запуска этого каждую минуту.

* * * * * ~/delta-sync.sh

Вывод можно контролировать с помощью следующей команды (я использую RHEL 8, см. руководство по вашей ОС для вывода cron)

$ tail -f /var/log/cron | grep CRON

Это пример журнала синхронизации.

CMD (~/cron/dsync.sh)
CMDOUT (INFO: Updated log registry to use new timestamp on next run.)
CMDOUT (INFO: Created sync directory: /home/ec2-user/cron/dump/2020-11-03T19:01:01Z)
CMDOUT (Fetching oplog in range [2020-11-03T19:00:01Z - 2020-11-03T19:01:01Z])
CMDOUT (2020-11-03T19:01:02.319+0000#011dumping up to 1 collections in parallel)
CMDOUT (2020-11-03T19:01:02.334+0000#011writing local.oplog.rs to /home/ec2-user/cron/dump/2020-11-03T19:01:01Z/local/oplog.rs.bson.gz)
CMDOUT (2020-11-03T19:01:04.943+0000#011local.oplog.rs  0)
CMDOUT (2020-11-03T19:01:04.964+0000#011local.oplog.rs  0)
CMDOUT (2020-11-03T19:01:04.964+0000#011done dumping local.oplog.rs (0 documents))
CMDOUT (INFO: Dump success!)
CMDOUT (INFO: Replaying oplogs...)
CMDOUT (2020-11-03T19:01:05.030+0000#011using write concern: &{majority false 0})
CMDOUT (2020-11-03T19:01:05.054+0000#011will listen for SIGTERM, SIGINT, and SIGKILL)
CMDOUT (2020-11-03T19:01:05.055+0000#011connected to node type: standalone)
CMDOUT (2020-11-03T19:01:05.055+0000#011mongorestore target is a directory, not a file)
CMDOUT (2020-11-03T19:01:05.055+0000#011preparing collections to restore from)
CMDOUT (2020-11-03T19:01:05.055+0000#011found collection local.oplog.rs bson to restore to local.oplog.rs)
CMDOUT (2020-11-03T19:01:05.055+0000#011found collection metadata from local.oplog.rs to restore to local.oplog.rs)
CMDOUT (2020-11-03T19:01:05.055+0000#011restoring up to 4 collections in parallel)
CMDOUT (2020-11-03T19:01:05.055+0000#011replaying oplog)
CMDOUT (2020-11-03T19:01:05.055+0000#011applied 0 oplog entries)
CMDOUT (2020-11-03T19:01:05.055+0000#0110 document(s) restored successfully. 0 document(s) failed to restore.)
CMDOUT (INFO: Restore success!)

Вы можете остановить этот скрипт после проверки того, что больше не создается oplogs, т. е. когда исходная БД отключилась.

На этом полное руководство по миграции данных MongoDB с самостоятельным размещением завершается. Если вы хотите узнать больше о MongoDB, вот полезный ресурс о том, как использовать MongoDB в качестве источника данных в goLang.

Первоначально опубликовано на https://www.loginradius.com.