【AWS】DMSを使ったPostgreSQLのデータ移行と双方向レプリケーション
AWS間の環境移行に伴い、DBのデータ移行並びに移行中の新旧DBのデータ同期の手法としてAWSのDMS(Database Migration Service)を採用した。
今回はブルーグリーンデプロイ方式によりなるべくダウンタイムを出さないようにするというのが要件だった。具体的にはELBの加重ターゲティングを用いて新旧環境のEKSにトラフィックを分散し、徐々に新環境への比重を上げていくというものだ。その上で最初は新旧DBどちらも稼働し更新されるため相互に同期を行い、DB間の整合性を保つ必要がある。
そのためDMSの変更のみをレプリケートするCDC機能を用いて相互レプリケーションの設定を行った。
まず大まかなDMSの設定の流れを説明する。
①レプリケーションインスタンスを作成する。
②エンドポイントを作成する。
③移行タスクを作成する。
また前提条件として以下があげられる。
①RDS/auroraのパラメータグループにて論理レプリケーションを有効にする設定をする。(レプリケーションを行う場合でフルロードのみの場合は不要)
②ソース/ターゲットエンドポイントに設定するRDSやauroraとDMSのレプリケーションインスタンス間で通信できること。またSGで許可されていること。
それでは今回行った設定やつまづきポイントを紹介していく。
①レプリケーションインスタンス
内部的にはEC2が使われているため、構築の仕方は通常のインスタンス作成に近い。インスタンスクラス(CPUやメモリ性能)、ストレージ容量を指定する。こういったリソース不足で移行に失敗する場合はインスタンスクラスやストレージ量の見直しが必要である。ただ特段構築における留意点はない。
②エンドポイント
移行タスクを実行するにあたってソースエンドポイントとターゲットエンドポイントを作成する必要がある。エンドポイントにはRDSインスタンスのエンドポイントURL(踏み台から-hで指定するホスト名のこと)やDBユーザ/パスワード情報、ポート、DB名を設定する。
ハマったポイントとしては接続のテストがエラーになったことだ。
RDSのSGの設定がうまくいってなかったりルーティングできていないとレプリケーションインスタンスとエンドポイント間で通信できずエラーになる。しかしどれだけその設定を見直してもエラーは解消されなかった。
そこでSSLモードを要求する(required)を設定するとこのエラーは解消された。SSLモードによってエンドポイントへの通信が暗号化される。
また論理レプリケーションスロットが増大し、RDSのストレージがフルになってしまうという課題が発生した。
DMSタスクが通常実行されているときには、論理レプリケーションのためのWALログファイルが、CDCの差分がターゲットに適用されるたびに削除される仕組みになっている。しかし、DMSタスクが停止しているときに論理レプリケーションの設定が有効になっていると、このWALの削除が行われずに、ストレージ使用量が著しく増えてしまう。
以下のSQLで論理レプリケーションスロットの状態を確認し、ActiveがF表示(False)になっていて、容量が大きい論理レプリケーションスロットを削除することで暫定対処できる。
psql> SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn))AS replicationSlotLag,active FROM pg_replication_slots;
以下で削除する。
psql> SELECT pg_drop_replication_slot('論理レプリケーションスロットの名前');
DMS側の設定としてはソースエンドポイントの追加の接続属性に、以下を追加する。
WALのハートビート機能をオンにすることで、アイドル状態の論理レプリケーションスロットが古いWALログを保持しなくなる。
HeartbeatEnable: true
③移行タスク
今回は双方向レプリケーションするために、まず旧DBから新DBにデータを移行し、同期を行うためFullload-and-cdcのタスクを作成した。そして新DBから旧DB への同期を行うためにcdcのタスクを作成した。
そのためそれぞれのタスク用にエンドポイントを作成した。
ソース/ターゲットで1セットであり、1つのタスクに紐づくため、合計エンドポイントは4つ作成した。
今回ハマったポイントとしては、まずCDCカスタム開始についてだ。
最初、このCDCカスタム開始の設定を有効にしていたが、タスクが一向に正常完了せず、失敗してしまっていた。
AWS公式サポートに問い合わせた結果、この設定が不要であったようだ。
今回の様に0からFullLoadでデータを移行する場合はオフの設定で良いだろう。
次にハマったポイントは、制御テーブルのエラーだ。DMSが作成する移行に関する情報を書き込むテーブルが存在しないという旨のエラーが発生した。
こちらはDB側の設定が原因だった。デフォルトスキーマの設定を特有のスキーマに変更したため、その制御テーブルがカレントスキーマに作成されていた。しかしDMS側でそのスキーマを指定する設定をしていなかったため、デフォルトのpublicスキーマにテーブルを見に行ってしまっていた。
つまりデフォルトスキーマをpublicから特定のものに変えている場合は、以下のタスク設定のパラメータにスキーマ名を明示的に指定しておく必要がある。
"ControlTableSettings": {"ControlSchema":"カレントスキーマ名"}
このほかにもタスクには細かい設定を施すことができる。
例えば特定のテーブルのみ、移行や同期の対象外とするといった細かい制御も可能だ。
マッピングルールを編集すると実現できるので詳しくは公式情報を参照すると良い。
また私の失敗を最後にもう1つだけ紹介するとしたら、CDCタスクに設定した検証(データ移行なし)だ。
DMSには移行や同期に関する検証する機能があり、結果の分析やエラーの調査に役立つが、この設定を施すと実際のデータ移行がされない。
これはデータの移行をせずに検証のみを実行する機能であり、調査や検証には有効だが、本番のレプリケーション時には不適切なので、オフにすることをお勧めする。
④最後に
DMSの実行はハードルが高く、DBの設定や環境によってさまざまな課題が生じるだろう。
そんな時AWS公式サポートはログなどから非常に具体的かつ的確な解決法を提案してくれる。
そのうえでDMSのログ取得は必須である。
Cloud Watch Logsにログを出力する為にIAMロールが必要なので忘れずに作成しておくとよい。(作成のみで良い)
またタスクの設定でログのレベルを修正できるが。何かエラーが発生した場合は「詳細なデバッグレベル」のログを取得し、そのログを公式に連携すると良いだろう。
では最後に簡潔にDMSの実相の流れをまとめる。
①DMSレプリケーションインスタンスを作成する。
②ソース/ターゲットエンドポイントを作成する。
→接続テストを行う。エラーになる場合はルーティングとSG、DB認証情報に不備ないか確認
③ソース/ターゲットDBに論理レプリケーションを有効にする設定を行う。
→RDSならParameterGroupを修正してインスタンス再起動。RDSPostgreSQLの場合「rds.logical_replication: 1」
④移行タスクを作成
⑤タスクの実行
この記事が気に入ったらサポートをしてみませんか?