mongomirrorを用いてAWS上のMongoDBからAtlasにデータをインポートする


関連

MongoDB AtlasのLiveMigrationを用いるときの覚書
AWS上のMongoDBをAtlasにLiveMigrationする
NLBでTLS終端を行いAtlasのLiveMigrationを行う


経緯

Atlas提供の、LiveMigrationを利用した場合にエラーが発生することが何回かあった。

LiveMigration側でエラーが発生するとユーザー的にはブラックボックスで Troubleshootingやチャットサポートでは解決策を見い出せなかったので、mongomirrorを用いてデータをインポートすることにした。

手順

mongomirrorを動かすインスタンスを用意する

To avoid contention for network and CPU resources, do not run mongomirror on the same hosts that provide your replica set’s mongod instances.

mongomirror must have network access to the source replica set.
mongomirror must have network access to the target cluster.
mongomirror has approximately the same performance impact on your source replica set as a secondary:
For the initial sync stage, the load scales with the size of your data set.
Once an initial sync completes, the load scales with oplog gigabytes used per hour.

EC2上のDB、およびAtlasに接続できる場所である必要がある = appサーバと同じサブネット内に、 DBサーバと同じスペックでインスタンスを作成する

mongomirrorのインストール


mkdir mongomirror_work
cd mongomirror_work

curl https://s3.amazonaws.com/mciuploads/mongomirror/binaries/linux/mongomirror-linux-x86_64-enterprise-amzn64-0.8.0.tgz -o mongomirror-linux-x86_64-enterprise-amzn64-0.8.0.tgz
tar -zxvf mongomirror-linux-x86_64-enterprise-amzn64-0.8.0.tgz


curl https://downloads.mongodb.org/linux/mongodb-shell-linux-x86_64-amazon-4.2.0.tgz -o mongodb-shell-linux-x86_64-amazon-4.2.0.tgz
tar -zxvf mongodb-shell-linux-x86_64-amazon-4.2.0.tgz

ソース側のDB(EC2)に移行用のユーザーを作成する。

Set up MongoDB user in the source replica set


use admin
db.createUser(
  {
    user: "mySourceUser",
    pwd: "mySourceP@$$word",
    roles: [ "clusterMonitor", "readAnyDatabase" ]
  }
)

Atlas側にAtlasAdmin権限でユーザーを作成する

Set up MongoDB user in the target Atlas cluster

ここで作成するユーザーは、Save as temporary user にチェックを入れる

疎通確認


mongodb-linux-x86_64-amazon-4.2.0/bin/mongo "mongodb+srv://<Atlasのホスト>/admin"  --username <Atlasに作成したユーザー>

mongomirrorの起動

参考 https://www.slideshare.net/mongodb/mongodblocal-seattle-2019-best-practices-for-migrating-to-mongodb-atlas


nohup mongomirror-linux-x86_64-enterprise-amzn64-0.8.0/bin/mongomirror \
--host <srcのレプリカセット名>/srcのホスト1:27017,srcのホスト2:27017,srcのホスト3:27017 \
--username "<srcに作成した移行用のユーザー>" \
--password "<srcに作成した移行用のユーザーのパスワード>" \
--authenticationDatabase "admin" \
--destination "<Atlas上のレプリカセット名>/<Atlasクラスターのホスト1>:27017,<Atlasクラスターのホスト2>:27017,<Atlasクラスターのホスト3>:27017" \
--destinationUsername "<Atlas側に作成したユーザー>" \
--destinationPassword "<Atlas側に作成したユーザーのパスワード>" \
--httpStatusPort 8000 \
-j 16 > mongomirror.log 2>&1 &

この際、Atlas上のレプリカセット名や、接続情報の確認方法は
https://docs.atlas.mongodb.com/import/mongomirror/#copy-the-target-cluster-host-information
をよく読む。

接続情報が間違っていると


2019-10-08T05:27:30.881+0000    Error initializing mongomirror: could not initialize destination connection: could not connect to server: server selection error: server selection timeout
current topology: Type: ReplicaSetNoPrimary
Servers:

のようなエラーがでてmongomirrorが止まる

-jオプションについて

collectionコピーの並列度を決める。
numParallelCollections

--numParallelCollections , -j
Default: 4

The number of collections to copy and restore in parallel.

サポートに聞いたところ、

we recommend this parameter to be in line with the number of CPU cores on the host machine hosting mongomirror. 

とのことなので、CPUサイズに合わせる。
デフォルトは4。おそらくLiveMigrationも裏ではmongomirrorを4で起動しているのではないかと思う。
今回16にすると、LiveMigrationでは16hかかっていたものが6hほどに短縮された。

mongomirrorのログの読み方

initializing ~ initial syncのログ


nohup: ignoring input
mongomirror version: 0.8.0
git version: a5cbb2d5babea8ed87191b31b12ffc6f3a3fa485
Go version: go1.12.4
   os: linux
   arch: amd64
   compiler: gc
2019-10-08T05:31:42.724+0000    Initializing HTTP status service on port 8000
2019-10-08T05:31:42.801+0000    Attempting initial sync from: 10.0.1.17:27017
2019-10-08T05:31:43.015+0000    Creating collection <DB名>.<コレクション名AAA>
2019-10-08T05:31:43.015+0000    Creating collection <DB名>.<コレクション名BBB>
2019-10-08T05:31:43.078+0000    Copying documents to collection <DB名>.<コレクション名AAA>
2019-10-08T05:31:43.116+0000    Copying documents to collection <DB名>.<コレクション名BBB>
2019-10-08T05:31:46.015+0000    [........................]       <DB名>.<コレクション名AAA>   39316/1033602  (3.8%)
2019-10-08T05:31:46.015+0000    [#.......................]       <DB名>.<コレクション名BBB>   50015/1161614  (4.3%)

コレクション毎の進捗がインジゲーター風に3秒ごとに出力される。
ここでJオプションで指定した並列度が効いてくる。

indexのコピー

documentのコピーが終わるとindexの構築が始まる


2019-10-08T05:43:32.944+0000    Copied 11043565 documents to <DB名>.<コレクション名AAA>
2019-10-08T05:43:32.944+0000    [########################]  <DB名>.<コレクション名AAA>  11043565/11043565  (100.0%)
2019-10-08T05:43:32.993+0000    Tailing the oplog on the source cluster starting at timestamp: {1570512697 1}
2019-10-08T05:43:32.994+0000    Oplog tailer has shut down. Oplog applier will exit.
2019-10-08T05:43:32.994+0000    Current lag until the end of initial sync: 0s
2019-10-08T05:43:33.032+0000    createIndexes for collection: `<DB名>.<コレクション名AAA>`, finished in 36.390104ms
2019-10-08T05:43:33.032+0000    createIndexes for collection: `<DB名>.<コレクション名BBB>`, finished in 36.834095ms

ここで注意したいのが、createIndexes for collection のログ出力は、index構築完了後に表示されるので、大きなコレクションでIndex作成自体に数分かかるものがある場合、ログの出力が止まってしまう。
ログ出力がない場合でもmongomirrorのプロセスは生きているのでそんなときはhttpサーバー機能(後述)で現在のステータスを確認できるので慌てない。

initial sync ~ oplog syncのログ

documentのコピー、Indexの構築がおわると、mongomirrorはoplog sync状態にはいる。
このlag時間が0sの場合にカットオーバーすることができる。


2019-10-08T06:00:48.161+0000    Index builds completed.
2019-10-08T06:00:48.161+0000    Initial sync from 10.0.1.17:27017 completed at oplog timestamp: {{1570513407 1} {1570513407 1}}
2019-10-08T06:00:48.161+0000    Proceeding to tail oplog.
2019-10-08T06:00:48.174+0000    Current lag from source: 17m20s
2019-10-08T06:00:48.174+0000    Tailing the oplog on the source cluster starting at timestamp: {1570513407 1}
2019-10-08T06:00:58.185+0000    Current lag from source: 0s
2019-10-08T06:01:08.175+0000    Current lag from source: 0s

httpサーバー機能によるステータス確認

起動オプションで指定した、--httpStatusPort 8000 に対して、GETリクエストを行うことで、mongomirrorのプロセスの現在の状態を知ることができる。


curl -X GET http://localhost:8000 | python -m json.tool

{
    "details": {
        "<DB名>.<コレクション名AAA>": {
            "complete": true,
            "createIndexes": 2
        },
        "<DB名>.<コレクション名AAA>": {
            "complete": true,
            "createIndexes": 4
        },
        ....
    },
    "phase": "copying indexes",
    "stage": "initial sync"
}

mongomirror の停止


ps aux | grep mongomirror
kill <pid>

2019-10-08T06:10:28.175+0000    Current lag from source: 0s
2019-10-08T06:10:38.175+0000    Current lag from source: 0s
2019-10-08T06:10:48.130+0000    signal 'terminated' received; attempting to shut down
2019-10-08T06:10:48.130+0000    Quitting...
2019-10-08T06:10:48.131+0000    Current lag from source: 0s
2019-10-08T06:10:49.130+0000    Timestamp file written to /home/ec2-user/mongomirror_work/mongomirror.timestamp.

このとき作成されたmongomirror.timestampは次回のmongomirror実行時に、bookmarkFileオプションとして指定することで、続きから実行することができる。

--bookmarkFileを指定して起動したときのログは以下のような出力となる。

git version: a5cbb2d5babea8ed87191b31b12ffc6f3a3fa485
Go version: go1.12.4
   os: linux
   arch: amd64
   compiler: gc
2019-10-10T01:51:16.723+0000    Initializing HTTP status service on port 8000
2019-10-10T01:51:16.791+0000    Read timestamp from bookmark file: {1570671675 1}
2019-10-10T01:51:16.791+0000    Proceeding to tail oplog.
2019-10-10T01:51:16.792+0000    Current lag from source: 10m0s
2019-10-10T01:51:16.792+0000    Tailing the oplog on the source cluster starting at timestamp: {1570671675 1}
2019-10-10T01:51:26.803+0000    Current lag from source: 0s
2019-10-10T01:51:36.793+0000    Current lag from source: 0s