AWS DMSを使ってRDS for PostgresからDynamoDBにデータ移行

## はじめに

Postgresqlに保存してあったデータをDynamoDBに移行させるために、AWSのDMS(Database Migration Service)を使ってみた時の、メモをまとめた記事である。

## 背景

クローリングしたデータをRDS for Postgresqlに保存していて、そのデータの利用してAPI GatewayとLambdaを使ってAPIサーバを作成しようと思っていたのだが、RDSとLambdaは相性が良くないということが判明した(接続数の問題などで)。
しかも、DynamoDBを使えば、エンドポイントがつくられるので、わざわざLambdaで関数作る必要無いことに気がついたので、RDS to DynamoDBへの移行計画を立てることにした。

調べているとAWS DMSという、いかにもなサービスがあったので使ってみることにしたというのが、事の顛末である。

## AWS DMSについて

AWS DMS(Database Migration Service)は、Databaseの移行を簡単に行えるサービスである。
Mysql to Mysqlのような同種DB間のデータ移行にも当然対応しているが、Postgresql to DynamoDBのような異種DB間のデータ移行にも対応している。
利用シーンとしては、オンプレのMySQLサーバをRDS for MySQLに移行する際や、RDS for PostgresqlをAurora for Postgresqlに移行する際に使用する。
また、一度だけのデータ移行にも使えるが、継続的なレプリケーションにも対応しているので、開発/テスト環境の同期などにも使うことができる。
ちなみに、Aurora、Redshift、DynamoDBに移行する場合はDMSを6ヶ月間無料で使うことができる。今回はDynamoDBに移行させるので、試すにはピッタリだった。

※ 追記) DynamoDBの使用量は無料ではないので注意すること！

## 移行手順

### 1. レプリケーションインスタンスの作成

DMSでデータ移行するためにはレプリケーション用のインスタンスを作成する必要がある。
これは、DMSの設定画面から簡単に設定できる。

AWSコンソールから
「Database Migration Service >> レプリケーションインスタンス >> レプリケーションインスタンスの作成」
を選択。

すると以下のような画面が出てくる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/2d90141d-1d56-7f11-d92f-bbe46a83b07e.png)

- 名前:
    - レプリケーションインスタンスの名前
- 説明:
    - レプリケーションインスタンスの説明
- インスタンスクラス:
    - EC2でいうインスタンスタイプ
    - 2018年1月現在ではt2とc4インスタンスが選べる
    - 料金は[こちら](https://aws.amazon.com/jp/dms/pricing/)
- レプリケーションエンジンのバージョン:
    - バージョン2.4.0を選択するとデータの検証ができるらしい
    - 古いものを選ぶ理由は今のところ無いので新しいバージョンを選ぶ
- vpc:
    - レプリケーションインスタンスを置くvpc
    - 移行元か移行先どちらかのvpcに置くと色々と楽
        - ちなみに、移行元か移行先のどちらかがAWSサービスでないとDMSは使用できない
- マルチAZ:
    - レプリケーションインスタンスをマルチAZ配置にする場合有効にする
- パブリックアクセス可能:
    - レプリケーションインスタンスをインターネットアクセス可能にする場合有効にする
    - VPCでサブネットやインターネットゲートウェイをしっかりと設定しているのであれば有効にする必要がない(はず)

### 2. ソースエンドポイントの作成

ソースエンドポイントでは移行元のDBへのアクセス方法を設定する。
今回はRDS for Postgresqlが移行元DBになる。

AWSコンソールから
「Database Migration Service >> エンドポイント >> エンドポイントの作成」
を選択。

すると以下のような画面が出てくる
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/37994933-2020-3599-aba2-d25f8d7682f0.png)

- エンドポイントタイプ:
    - ソースかターゲットを選択
    - 移行元がソースなので、ここではソースを選択
- エンドポイント識別子:
    - 作成するエンドポイントの名前
    - 同じ名前のエンドポイントは作成できない
    - 名前が同じでなければなんでも良い
- ソースエンジン:
    - 移行元のデータベースエンジン
    - 今回はPostgresqlなので、postgesを選択
- サーバ名:
    - 移行元のサーバ名
    - オンプレの場合であれば、そのサーバのアドレス
    - RDSであれば、インスタンスのエンドポイントを入力すれば良い
- ポート:
    - 移行元DBのポート番号
    - 今回はPostgresのデフォルトポートの5432を入力
- SSLモード:
    - 移行時の通信を暗号化するかを選択する
    - SSLを有効にした場合には、安全にはなるがオーバーヘッドが増えるので必要化判断して有効化すること
    - 選択した項目によりサーバ証明書が必要になる
    - 選択項目は以下の4つ
        - none: 暗号化しない
        - require: 暗号化される。証明書は不要。
        - verify-ca: 暗号化される。証明書が必要。
        - verify-full: 暗号化される。証明書とサーバのホスト名が一致するか確認される
- ユーザ名
    - 移行元DBのユーザー名
    - ここでマスターユーザを選択しないと色々と面倒なので、マスターユーザを選択すること
- パスワード
    - 先程選択したユーザのパスワード
    - 「&」や「+」のような記号はエスケープしないと使えない
    - 「&」や「+」が入る場合は全てを波括弧「{}」で括ること
- データベース名
    - 移行したいデータベース名


一通りの設定をした後、接続テストができる。
ここで接続する元は、先程作成したレプリケーションインスタンスになるため、セキュリティーグループやファイアーウォールでアクセス制限をしている場合は、レプリケーションインスタンスがアクセスできるようにする必要がある。

### 3. ターゲットエンドポイントの作成

こちらでは移行先のDBのアクセス方法を設定する。
今回の移行先はDynamoDBになる。

設定方法は基本的にソースエンドポイントと同じだが、ターゲットエンドポイントにDynamoDBを設定した場合には、サービスのアクセスロールだけ指定すれば簡単に設定することができる。

AWSコンソールから
「Database Migration Service >> エンドポイント >> エンドポイントの作成」
を選択。

エンドポイントタイプをターゲットを選択し、ターゲットエンジンをDynamoDBにすると、以下のような画面が出てくる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/12382102-0e1b-ea22-714f-0befc4a0732c.png)

- エンドポイント識別子:
    - エンドポイントの名前
    - 既に作成済みのエンドポイントと重複しなければ良い
- ターゲットエンジン:
    - 移行先のデータベース
    - 今回はdynamodbを選択
- サービスへのアクセスロールのARN
    - DynamoDBのアクセス権限があるIAM RoleのARN
    - ポリシーは細かく設定できるけど、めんどくさかったので以下のポリシーをアタッチ
        - AmazonDynamoDBFullAccess
        - AmazonDMSVPCManagementRole(いらないかも...?)

これも、必ず接続テストを行うこと。
DynamoDBに関しては、設定したロールが正しいアクセス権限を持っていれば問題なく接続できる(はず)

### 4. タスクの作成

移行するための最後の設定としてタスクを作成する。

AWSコンソールから
「Database Migration Service >> タスク >> タスクの作成」
を選択。

すると以下のような画面が出てくる。タスクの設定だけはちょっと長いので分割して説明する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/55c168af-6c63-1c99-25b9-329233d7605f.png)

- タスク名:
    - タスクの名前
    - これはなんでも良い
- レプリケーションインスタンス:
    - このタスクで使用するレプリケーションインスタンス
    - 今回は `1.` で作成したものを使用する
- ソースエンドポイント:
    - このタスクの移行元となるエンドポイント
    - 今回は `2.` で作成したものを使用する
- ターゲットエンドポイント:
    - このタスクの移行先となるエンドポイント
    - 今回は `3.` で作成したものを使用する
- 移行タイプ:
    - このタスクで継続的にデータのレプリケーションを行うか設定する
    - 項目は以下の3つ
        - 既存のデータを移行する
            - 初回の移行のみ実行する
        - 既存のデータを移行し、継続的な変更をレプリケートする
            - 初回の移行を実行し、その後も継続的にレプリケートされる
        - データ変更のみをレプリケートする
            - データ変更のみをレプリケートされる
            - 通常、同種DB間の移行にのみ適用されるらしい
            - どういう時に使うかはよくわからなかった
    - 今回は、一度だけ移行ができれば良いので、「既存のデータを移行する」を選択
- 作成時にタスクを実行
    - タスクの作成と同時にタスクを実行したければチェックをつける


次はタスク設定の画面
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/af6cfedf-519d-6659-f738-9850b5f572da.png)

- ターゲットテーブル作成モード:
    - タスク実行時に移行先のテーブルをどうするかを設定する
    - 設定項目は以下の3つ
        - 何もしない
            - 移行先にテーブルがない場合作られる
        - ターゲット上のテーブルをDROP
            - 移行先のテーブルを全部DROPする
        - TRUNCATE
            - メタデータに影響を与えないよう、TRUNCATEされる
- レプリケーションにLOB列を含める:
    - データ移行の際にLOB(Large Object)を含めるか設定する
    - 画像をバイナリで保存している際などに、そのデータを移行するか設定する
    - 以下の設定項目がある
        - LOB列を含めない
            - LOB列を移行対象から外す
        - 完全LOBモード
            - サイズに関係なくLOB列を移行対象に含める
            - チャンク単位で送信するため、低速
        - 制限付きLOBモード
            - 次で設定する最大LOBサイズ以上のデータを削除して送信する
            - 完全LOBモードに比べると高速
- 最大LOBサイズ（KB):
    - レプリケーションにLOB列を含めるに制限付きLOBモードを選択した時の最大LOBサイズ
- 検証の有効化:
    - 移行元と移行先でデータを比較し検証するかどうかを選択する
- ロギングの有効化:
    - 移行時のログをCloudWatch Logsに吐くかを選択する

最後にテーブルマッピングの設定
![image.png](https://qiita-image-store.s3.amazonaws.com/0/120358/752f3f26-d4c2-f76c-73a6-f58f65fec105.png)

- 選択ルールを設定する。
- このルールに基いて、除外するテーブルやカラムを決定する。
- ワイルドカードを使用できるので、まぁまぁ柔軟に設定できそう。
- 最低一つは設定しなければいけないっぽい。
- 一旦、デフォルトの状態のまま選択ルールの追加する。
- 選択ルールを一つでも追加すると、変換ルールも追加できるようになる。
    - 名前の変更とか、テーブルや列の削除しかできないので、結構限定的。

以上が全て設定できたら、タスクの作成ボタンを押下。
「作成時にタスクを開始」にチェックが入っている場合にはすぐにタスクが実行される。

## 所感

実際にAWS DMSを使ってみて、かなり簡単に異種DB間のデータ移行を実現することができた。
データ量もあまり多くなかったため、10分程度で全てのデータ移行が完了していた。
コストも今回は無料だったし、実際に課金されても低コストで使用することができそう。

## 追記

dynamodbのwrite capacityとread capacityの無料枠を大幅に超えて課金されてた...。
約46USD...、血と涙の教訓。


## 参考

- [ソースとしての Amazon RDS PostgreSQL DB インスタンスの設定
](https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Source.PostgreSQL.html#CHAP_Source.PostgreSQL.RDSPostgreSQL)
- [AWS Database Migration Service のターゲットとしての Amazon DynamoDB データベースの使用
](https://docs.aws.amazon.com/ja_jp/dms/latest/userguide/CHAP_Target.DynamoDB.html)