[DMS] MongoDBからRDS MySQLへのレプリケーションを試す

2017.04.30

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

こんにちは、菊池です。

MongoDBからのDMSレプリケーション、S3ターゲットに続きMySQLでも試してみました。これまでの記事は以下を参照ください。

検証

SourceとしてEC2で動作するMongoDBのレプリカセット、TargetとしてRDS MySQLインスタンスを利用します。

  • Source
    • MongoDB 3.4.2
    • レプリケーションモード:テーブルモード
  • Target
    • RDS for MySQL 5.6.27

dms-mongo-to-mysql

初期データのマイグレーション

まずはデータを1つMongoDBに挿入し、レプリケーションを実行します。

s0-rs0:PRIMARY> use main
switched to db main
s0-rs0:PRIMARY>
s0-rs0:PRIMARY> db.users.insert(
...   {
...     userid : 001,
...     name : "hoge1",
...     joined : ISODate("2017-04-01"),
...     likes : [ "tennis", "golf", "swimming" ]
...   }
... );
WriteResult({ "nInserted" : 1 })
s0-rs0:PRIMARY>
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("5905346cb1ae627be955aca4"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }

この状態でレプリケーションタスクを実行します。移行先のMySQLでデータベースを確認します。

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| awsdms_control     |
| innodb             |
| main               |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

mainデータベースが作成されています。テーブルも確認してみます。

mysql> show tables from main;
+----------------+
| Tables_in_main |
+----------------+
| users          |
+----------------+

usersテーブルが作成されました。レコードを確認します。

mysql> select * from users;
+--------------------------+--------+-------+---------------------+----------------------------------+
| $OID:_id                 | userid | name  | joined              | $ARRAY:likes                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
| 5905346cb1ae627be955aca4 |      1 | hoge1 | 2017-04-01 00:00:00 | [ "tennis", "golf", "swimming" ] |
+--------------------------+--------+-------+---------------------+----------------------------------+
1 row in set (0.00 sec)

レプリケーションが実行されました。配列の列は$ARRAYで定義されています。

CDCの実行

続けてMongoDBにデータを追加して、CDCが実行されることを確認します。

s0-rs0:PRIMARY> db.users.insert(
...   {
...     userid : 002,
...     name : "hoge2",
...     joined : ISODate("2017-04-01"),
...   }
... );
WriteResult({ "nInserted" : 1 })
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("5905346cb1ae627be955aca4"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
{ "_id" : ObjectId("59053611b1ae627be955aca5"), "userid" : 2, "name" : "hoge2", "joined" : ISODate("2017-04-01T00:00:00Z") }
s0-rs0:PRIMARY>

MySQLのデータを確認します。

mysql> select * from users;
+--------------------------+--------+-------+---------------------+----------------------------------+
| $OID:_id                 | userid | name  | joined              | $ARRAY:likes                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
| 5905346cb1ae627be955aca4 |      1 | hoge1 | 2017-04-01 00:00:00 | [ "tennis", "golf", "swimming" ] |
| 59053611b1ae627be955aca5 |      2 | hoge2 | 2017-04-01 00:00:00 | NULL                             |
+--------------------------+--------+-------+---------------------+----------------------------------+
2 rows in set (0.00 sec)

データが同期されています。挿入したデータになかった項目はNULLとなっています。

次に、型が異なるデータを挿入してみます。joindを文字列で挿入します。

s0-rs0:PRIMARY> db.users.insert(
...   {
...     userid : 003,
...     name : "hoge3",
...     joined : "2017-04-01",
...     likes : [ "tennis" ]
...   }
... );
WriteResult({ "nInserted" : 1 })
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("5905346cb1ae627be955aca4"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
{ "_id" : ObjectId("59053611b1ae627be955aca5"), "userid" : 2, "name" : "hoge2", "joined" : ISODate("2017-04-01T00:00:00Z") }
{ "_id" : ObjectId("59053671b1ae627be955aca6"), "userid" : 3, "name" : "hoge3", "joined" : "2017-04-01", "likes" : [ "tennis" ] }
s0-rs0:PRIMARY>

MySQL側では型が異なるとNULLとなっています。

mysql> select * from users;
+--------------------------+--------+-------+---------------------+----------------------------------+
| $OID:_id                 | userid | name  | joined              | $ARRAY:likes                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
| 5905346cb1ae627be955aca4 |      1 | hoge1 | 2017-04-01 00:00:00 | [ "tennis", "golf", "swimming" ] |
| 59053611b1ae627be955aca5 |      2 | hoge2 | 2017-04-01 00:00:00 | NULL                             |
| 59053671b1ae627be955aca6 |      3 | hoge3 | NULL                | [ "tennis" ]                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
3 rows in set (0.00 sec)

先ほどのデータを更新して、正しいデータ型にupdateします。

s0-rs0:PRIMARY> db.users.updateOne(
...   { userid : 003 },
...   { $set: { joined : ISODate("2017-04-01") } }
... );
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

更新が反映されています。

mysql> select * from users;
+--------------------------+--------+-------+---------------------+----------------------------------+
| $OID:_id                 | userid | name  | joined              | $ARRAY:likes                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
| 5905346cb1ae627be955aca4 |      1 | hoge1 | 2017-04-01 00:00:00 | [ "tennis", "golf", "swimming" ] |
| 59053611b1ae627be955aca5 |      2 | hoge2 | 2017-04-01 00:00:00 | NULL                             |
| 59053671b1ae627be955aca6 |      3 | hoge3 | 2017-04-01 00:00:00 | [ "tennis" ]                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
3 rows in set (0.00 sec)

削除も試してみました。

s0-rs0:PRIMARY> db.users.deleteOne(
...   { userid : 003 }
... );
{ "acknowledged" : true, "deletedCount" : 1 }
s0-rs0:PRIMARY> db.users.find()
{ "_id" : ObjectId("5905346cb1ae627be955aca4"), "userid" : 1, "name" : "hoge1", "joined" : ISODate("2017-04-01T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
{ "_id" : ObjectId("59053611b1ae627be955aca5"), "userid" : 2, "name" : "hoge2", "joined" : ISODate("2017-04-01T00:00:00Z") }
s0-rs0:PRIMARY>

削除もちゃんと同期されました。

mysql> select * from users;
+--------------------------+--------+-------+---------------------+----------------------------------+
| $OID:_id                 | userid | name  | joined              | $ARRAY:likes                     |
+--------------------------+--------+-------+---------------------+----------------------------------+
| 5905346cb1ae627be955aca4 |      1 | hoge1 | 2017-04-01 00:00:00 | [ "tennis", "golf", "swimming" ] |
| 59053611b1ae627be955aca5 |      2 | hoge2 | 2017-04-01 00:00:00 | NULL                             |
+--------------------------+--------+-------+---------------------+----------------------------------+
2 rows in set (0.00 sec)

まとめ

MongoDBからMySQLへのデータレプリケーションを試しました。

データモデルが異なるデータベースに対しても、一部制約はありつつも継続的なレプリケーションが可能です。移行だけでなく、フロント、非同期な集計、分析用途など、目的に応じて適切なデータベースを使っていくことも可能になります。