MongoDB Atlas への移行ツール:mongomirror を試してみた

2017.03.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、菊池です。

MongoDB のマネージドサービス:MongoDB Atlasへのマイグレーションツール、mongomirrorを試してみましたのでレポートします。

Migrate with mongomirror | MongoDB Atlas

mongomirror

mongomirrorはオンプレやクラウド環境で稼働する、MongoDBのデータをMongoDB Atlasへ移行するツールです。

AWSのDatabase Migration Serviceのように、ワンタイムの一括コピーと、オンラインでの継続的レプリケーションの両方が可能です。

前提条件

ソースデータベース:

  • MongoDB 3.0以降であること
  • レプリカセット構成であること

ターゲットデータベース:

  • MongoDB 3.4の最新版であること
  • レプリカセットのAtlas Clusterであること
  • 無償版以外のクラスタサイズ

レプリケーションで使われるOplogを利用する仕組みのためか、ソース/ターゲット共にレプリカセット構成であることが必須です。

また、mongomirrorを実行するインスタンスから、ソース/ターゲットの両方に接続可能である必要があります。

試してみた

早速試してみました。

ソースデータベース

まずはソースのデータ確認です。以下のように、mainデータベースにusersコレクションが存在しています。

s0-rs0:PRIMARY> use main
switched to db main
s0-rs0:PRIMARY> show collections
users
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ed"), "userid" : 10000, "name" : "hoge1", "age" : 19 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ee"), "userid" : 20000, "name" : "hoge2", "age" : 33 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ef"), "userid" : 30000, "name" : "hoge3", "age" : 41 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f0"), "userid" : 40000, "name" : "hoge4", "age" : 24 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f1"), "userid" : 50000, "name" : "hoge5", "age" : 50 }
{ "_id" : ObjectId("58dddfc8e87a9d84c86068f2"), "userid" : 60000, "name" : "hoge6", "age" : 16 }
s0-rs0:PRIMARY>

マイグレーションに必要なbackupロールのユーザを作成します。

s0-rs0:PRIMARY> db.createUser( { user: "mySourceUser", pwd: "xxxxxxxx", roles: [ "backup" ] } )
Successfully added user: { "user" : "mySourceUser", "roles" : [ "backup" ] }
s0-rs0:PRIMARY>

ターゲットデータベース

ターゲットデータベースは初期状態なのでデータが存在していません。

Cluster1-shard-0:PRIMARY> show dbs
admin  0.000GB
local  0.000GB
Cluster1-shard-0:PRIMARY>

ターゲットデータベースとなるAtlasにも、マイグレーションに必要なユーザを準備しておきます。必要なロールはreadWriteAnyDatabasedbAdminAnyDatabaseです。今回はadminユーザを利用しました。

mongomirrorの実行

mongomirrorのバイナリは公式からダウンロード可能です。今回はAmazonLinuxで実行しました。

ダウンロードしたmongomirrorを実行します。

$ mongomirror --host=s0-rs0/mongo1:27017,mongo2:27017,mongo3:27017 \
   -u "mySourceUser" \
   -p "xxxxxxxx" \
   --authenticationDatabase=admin \
   --destination=Cluster1-shard-0/cluster1-shard-00-01-xxxxxx.net:27017,cluster1-shard-00-01-xxxxxx.net:27017,cluster1-shard-00-02-xxxxxx.net:27017 \
   --destinationUsername=skikuchi \
   --destinationPassword=xxxxxxxx
017-03-31T05:20:17.029+0000   	Creating collection main.users
2017-03-31T05:20:17.145+0000   	Copying documents to collection main.users
2017-03-31T05:20:17.256+0000   	Dumped 6 documents to main.users
2017-03-31T05:20:17.257+0000   	Applying oplog entries that occurred during the initial sync, start: 6403528283916337153, end: 6403528283916337153
2017-03-31T05:20:17.267+0000   	Tailing the oplog
2017-03-31T05:20:17.267+0000   	Oplog tailer has shut down. Oplog applier will exit.
2017-03-31T05:20:17.373+0000   	Current lag from source: 0s
2017-03-31T05:20:17.383+0000   	Tailing the oplog

問題なければすぐに初期同期が完了します。ターゲット側Atlasでデータを確認してみます。

Cluster1-shard-0:PRIMARY> show dbs
admin  0.000GB
local  0.000GB
main   0.000GB
Cluster1-shard-0:PRIMARY> use main
switched to db main
Cluster1-shard-0:PRIMARY> show collections
users
Cluster1-shard-0:PRIMARY> db.users.find()
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ed"), "userid" : 10000, "name" : "hoge1", "age" : 19 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ee"), "userid" : 20000, "name" : "hoge2", "age" : 33 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ef"), "userid" : 30000, "name" : "hoge3", "age" : 41 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f0"), "userid" : 40000, "name" : "hoge4", "age" : 24 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f1"), "userid" : 50000, "name" : "hoge5", "age" : 50 }
{ "_id" : ObjectId("58dddfc8e87a9d84c86068f2"), "userid" : 60000, "name" : "hoge6", "age" : 16 }
Cluster1-shard-0:PRIMARY>

データが移行されています!

さらに継続歴レプリケーションを試すため、ソース側にデータをインサートしてみます。

s0-rs0:PRIMARY> db.users.insert({ userid:70000, name:"hoge7", age: 55 });
WriteResult({ "nInserted" : 1 })
s0-rs0:PRIMARY>
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ed"), "userid" : 10000, "name" : "hoge1", "age" : 19 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ee"), "userid" : 20000, "name" : "hoge2", "age" : 33 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ef"), "userid" : 30000, "name" : "hoge3", "age" : 41 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f0"), "userid" : 40000, "name" : "hoge4", "age" : 24 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f1"), "userid" : 50000, "name" : "hoge5", "age" : 50 }
{ "_id" : ObjectId("58dddfc8e87a9d84c86068f2"), "userid" : 60000, "name" : "hoge6", "age" : 16 }
{ "_id" : ObjectId("58dde7c9c1a34a4d588ce97d"), "userid" : 70000, "name" : "hoge7", "age" : 55 }
s0-rs0:PRIMARY>

ターゲット側で確認します。

Cluster1-shard-0:PRIMARY> use main
switched to db main
Cluster1-shard-0:PRIMARY> db.users.find()
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ed"), "userid" : 10000, "name" : "hoge1", "age" : 19 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ee"), "userid" : 20000, "name" : "hoge2", "age" : 33 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068ef"), "userid" : 30000, "name" : "hoge3", "age" : 41 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f0"), "userid" : 40000, "name" : "hoge4", "age" : 24 }
{ "_id" : ObjectId("58dddfc7e87a9d84c86068f1"), "userid" : 50000, "name" : "hoge5", "age" : 50 }
{ "_id" : ObjectId("58dddfc8e87a9d84c86068f2"), "userid" : 60000, "name" : "hoge6", "age" : 16 }
{ "_id" : ObjectId("58dde7c9c1a34a4d588ce97d"), "userid" : 70000, "name" : "hoge7", "age" : 55 }
Cluster1-shard-0:PRIMARY>

同期できました!

さいごに

いかがでしょうか。

mongomirrorを使うことで、簡単にAtlasに移行可能です。さらに、継続的レプリケーションも可能なので、稼働中のサービスも最小限の停止時間で同期が可能となります。