Mackerel チームで SRE を担当している
id:taxintt と申します。
はてなの SRE が毎月交代でブログ記事を書く Hatena Developer Blog の SRE 連載、7月号です。6月の記事は
id:masayoshi さんの NotebookLM で 社内のSREに関するブログや登壇資料を学習させ、SREのオンボーディングに活かせるか? - Hatena Developer Blog です。
Mackerel は、今年の4月にAPM・トレース機能を提供するシステムのメンテナンス作業を実施しました。このメンテナンスでは、AWS Database Migration Service(AWS DMS)を利用して APM・トレース機能で利用されている Amazon Aurora MySQL のデータを Amazon Aurora PostgreSQL に移行しました。本記事では、AWS DMS を利用したデータ移行の裏側についてお話しします。
データ移行の経緯
今回データを移行した Amazon Aurora MySQL クラスターは、監視プラットフォームサービス「Vaxila」の事業譲受に伴い、既存の Vaxila のアプリケーションに紐づく形で構築されたデータベースです。ユーザーが送信する OpenTelemetry のトレースデータを中心に、APM・トレース機能に関するデータを保存しています。一方で、Mackerel では主に Amazon Aurora PostgreSQL を利用しており、開発チームとして複数の RDBMS を運用している状態でした。
今回のデータ移行にあたっては、トレース・APM機能を提供するシステムで利用される DB について、開発チームとして習熟度が高い技術スタックに揃える方が望ましいと判断しました。また、トレースデータの送信量の増加に伴ってデータ移行の難易度が上がることは間違いなく、やるなら APM 機能の正式リリース前に実施すべきという結論に至ったため、データ移行の実施に踏み切りました。
AWS DMS について
Amazon Aurora MySQL から Amazon Aurora PostgreSQL への データ移行にあたっては AWS DMS を利用しました。AWS DMS を採用した理由としては、移行元の DB と移行先の DB が異なる RDBMS の場合のデータ移行をサポートしている点、社内に AWS DMS に関する知見があった点、データ検証などの DMS 特有の機能を使ってデータ移行の負担を軽減できる点が挙げられます。
AWS DMS(Database Migration Service)は、RDB、S3、Redshift などを対象としたデータ移行のためのサービスです。
What is AWS Database Migration Service? - AWS Database Migration Service

AWS DMS は主に下記のコンポーネントで構成されています。
- Replication Instance:データレプリケーションを実行するインスタンス
- Replication Task:データレプリケーションの実行定義
- Source Endpoint:移行元データベースへの接続定義
- Target Endpoint:移行先データベースへの接続定義
公式ドキュメントでは上記以外にも Database discovery、Schema and code migration が挙げられていますが、必須のコンポーネントとしては上記を覚えておけば十分かと思います。
Components of AWS DMS - AWS Database Migration Service
AWS DMS を利用したデータ移行の全体像
今回のデータ移行は下記のような順序で進めました。
- AWS 公式ドキュメントの確認
- 移行先の DB(PostgreSQL)のスキーマ作成
- DB Snapshot を利用した DMS の動作確認
- リハーサルも兼ねたステージング環境でのメンテナンス
- 本番環境でのメンテナンス
開発チームとして AWS DMS を利用したデータ移行の経験がなく、データ移行の実施期限を APM 機能の正式リリース前と決めていたため、余計な手戻りを避けることを念頭に置き、事前に AWS の公式ドキュメントを読み込みました。特に、下記のドキュメントを一通り読み込みました。
- Best practices for AWS Database Migration Service:AWS DMSを利用する上でのベストプラクティス集で、パフォーマンスの最適化やLOBの扱いなど、移行全般に役立つ情報がまとめられています。
- Using a MySQL-compatible database as a source for AWS DMS:移行元としてMySQL互換のデータベースを利用する場合のガイドで、
binlogの有効化といった前提条件や制約事項などが記載されています。 - Using a PostgreSQL database as a target for AWS DMS:移行先としてPostgreSQLを利用する場合のガイドで、データ型のマッピングや外部キーの扱いなどの注意事項について説明されています。
移行先の DB(PostgreSQL)のスキーマ作成はアプリケーションの修正においても必要なため、早い段階で実施しました。後述しますが、AWS DMS はデータ移行時に移行先の DB にテーブルを自動で作成できますが、意図通りのデータ型で作られない場合があります。そのため、移行先 DB で事前にテーブルを作成した上で、AWS DMS を利用してデータを正常に移行できるかを確認しました。
また、ステージング環境でのメンテナンスから本番でのメンテナンスまでは時間があったので、最新の DB Snapshot を利用したデータ移行のリハーサルを複数回実施しました。データ移行にかかる時間の正確な見積もりと意図しないデータによってデータ移行が失敗するリスクを最小限にするためにもなるべく最新のデータで検証することをお勧めします。
AWS DMS を利用したデータ移行の注意点
ここからは、AWS DMS を利用したデータ移行における考慮事項や注意点をいくつか挙げます。
データ移行タイプの選択
Replication Task の設定では、データ移行のタイプを以下の3種類から1つ指定できます。今回のメンテナンスでは、許容可能なサービス停止時間とデータ移行のタイプごとの前提条件などを総合的に判断し、Full Load タイプでのデータ移行を選択しました。
- Full Load:移行元の既存データを移行
- CDC:移行元で発生した更新データを移行
- Full Load + CDC:移行元の既存データを移行した後に、移行元で発生した更新データを移行
Full Load タイプでのデータ移行では、データ移行後に移行元の DB のデータが更新されても移行先の DB に変更が反映されないため、当日は DB への書き込みを止めた上でデータ移行を実施しました。Mackerelに送信されたトレースデータは API Gateway + Lambda で受信し、キューを経由して ECS で動いている worker が非同期で保存しています。メンテナンス時には送信されたトレースデータをキューに保持し続けて、データ移行が完了したタイミングで移行先の DB にトレースデータを保存するようにしました。これによって、サービスメンテナンスの間もユーザーはトレースデータを送信でき、送信されたトレースデータはデータロストすることなく移行後の DB に保存されるようになっています。
今回はFull Load でのデータ移行を選択しましたが、データ移行タイプの選択にあたっては、サービス停止時間の許容度合いや CDC でのデータ移行の前提条件を確認することをお勧めします。例えば、移行元の DB が MySQL かつ CDC でのデータ移行の場合には binlog を有効にする必要があり、また binlog に関連するパラメータもドキュメントに記載された値を設定する必要があります。
Using a MySQL-compatible database as a source for AWS DMS - AWS Database Migration Service
To use CDC, make sure to enable binary logging. To enable binary logging, the following parameters must be configured in MySQL's my.ini (Windows) or my.cnf (UNIX) file.
データ型の変換
先述したように、AWS DMS はデータ移行時に移行先の DB にテーブルを自動で作成できますが、意図通りのデータ型で作られない場合があります。そのため、移行先の DB で事前にテーブルを作成した上でデータを移行しました。Replication Task(Full Load タイプ)の設定では TargetTablePrepMode というパラメータで Full Load を実行する前に移行先の DB のテーブルをどのように処理するかを設定できます。今回は移行先の DB で事前作成したテーブルに対して、テーブルは残しつつデータを削除してからデータ移行を行う方式(truncate_before_load)を指定しました。
Full-load task settings - AWS Database Migration Service
TRUNCATE_BEFORE_LOAD – Data is truncated without affecting the table metadata.
AWS DMS は DMS 独自のデータ型を経由して、移行元の DB から移行先の DB にデータを移行します。前述の Source、Target Endpoint に関するドキュメントには、MySQL のデータ型と DMS 独自のデータ型のマッピング、DMS 独自のデータ型と PostgreSQL のデータ型のマッピングが記載されています。これらのマッピングは AWS DMS 利用時にサポートされるデータ変換のマッピングであり、これに該当しないものは正常にデータ変換されない可能性があります。そのため、移行元と移行先のDBで対応するデータ型を比較して、想定されるデータ型の変換が公式にサポートされているか調査し、事前に動作確認することが重要です。
- Using a MySQL-compatible database as a source for AWS DMS - AWS Database Migration Service
- Using a PostgreSQL database as a target for AWS Database Migration Service - AWS Database Migration Service
移行可能なオブジェクトの確認
データ移行時に事前確認すべき内容として、移行元の DB から移行できないオブジェクトの確認があります。MySQL の場合は、AUTO_INCREMENT 属性、インデックス、外部キーがAWS DMSで移行できないオブジェクトとして挙げられています。これらについては、DMS でのデータ移行とは別に移行先の DB に手動で作成する必要があります。
Using a MySQL-compatible database as a source for AWS DMS - AWS Database Migration Service
The AUTO_INCREMENT attribute on a column isn't migrated to a target database column.
Troubleshooting migration tasks in AWS Database Migration Service - AWS Database Migration Service
AWS DMS does not support migrating secondary objects such as indexes and foreign keys. To replicate changes made to child tables from a cascade update or delete operation, you need to have the triggering foreign key constraint active on the target table. To work around this limitation, create the foreign key manually on the target table.
データ移行時の制約
移行可能なオブジェクトに関しても、AWS DMSの設定や移行先のテーブル次第でデータ移行に失敗する場合があります。今回のデータ移行で考慮した一例として、Large binary objects(LOB)と外部キーに関する設定を挙げます。
LOB カラムについては、LOB の移行方法がいくつか存在し、指定した方法によって移行時の挙動が異なります。Full LOB mode は LOB のサイズに関係なく全ての LOB を移行します。一方で、Limited LOB mode は移行時のパフォーマンスを優先する代わりに、設定した最大データサイズを超える LOB は切り詰められます。今回のデータ移行では、LOB も含めて全てのデータを移行したかったため、Full LOB mode を選択しました。
Setting LOB support for source databases in an AWS DMS task - AWS Database Migration Service
また、移行後の DB で LOB カラムは nullable である必要があるため、Not null なカラムについては、テーブル作成時に nullable に一時的に設定した上でデータ移行後に Not null に変更するようにしました。
Best practices for AWS Database Migration Service - AWS Database Migration Service
This migration process for LOBs requires that, during the migration, all LOB columns on the target table must be nullable. This is so even if the LOB columns aren't nullable on the source table.
外部キーについては、外部キー制約を有効にしたテーブルを作成してデータ移行を行うと移行処理が失敗することがあったため、外部キーはデータ移行後に作成するようにしました。
In PostgreSQL, foreign keys (referential integrity constraints) are implemented using triggers. During the full load phase, AWS DMS loads each table one at a time. We strongly recommend that you disable foreign key constraints during a full load, using one of the following methods: ...
データバリデーションについて
データ移行後は、移行元の DB と移行先の DB でデータを突き合わせて、データの欠損や意図しない差分が存在しないことを確認する必要があります。AWS DMS では、データバリデーション機能があり、どのテーブルで不一致となったレコードが何件検出されたかという情報を確認できます。
また、どのレコードのどのカラムにおいてどのような差分が検出されたかという情報は移行先の DB に awsdms_validation_failures_v1 というテーブルが自動的に作成され、そのテーブルに格納されます。データ移行完了後にそのテーブルを参照することで、意図しない差分が存在するかを確認できます。
AWS DMS data validation - AWS Database Migration Service
主に確認するカラムは KEY, FAILURE_TYPE, DETAILS です。下記はドキュメントに記載されていたサンプルデータですが、「どのレコード」で「どのような差分が存在するか」を確認できることがわかるかと思います。
select * from awsdms_validation_failures_v1 where TASK_NAME = 'VFPFKH4FJR3FTYKK2RYSI'
TASK_NAME VFPFKH4FJR3FTYKK2RYSI
TABLE_OWNER DB2PERF
TABLE_NAME PERFTEST
FAILURE_TIME 2020-06-11 21:58:44
KEY_TYPE Row
KEY {"key": ["3451491"]}
FAILURE_TYPE RECORD_DIFF
DETAILS [[{'MYREAL': '+1.10106036e-01'}, {'MYREAL': '+1.10106044e-01'}],]
最新のアップデートとして、AWS DMS レプリケーションエンジンバージョン 3.6.1 以降で移行先の DB が PostgreSQL の場合に awsdms_validation_failures_v2 という名前でテーブルが作成されるようになりました。3.6.1からサポートされるようになった Data Resync の実行結果に関するカラムが追加されています。
During validation, in AWS DMS version 3.6.1 and above, DMS creates a new table at the PostgreSQL target endpoint: awsdms_validation_failures_v2. This tables consists of failures for all the DMS tasks that have data validation enabled. When the awsdms_validation_failures_v2 table is created, you should not drop or truncate the table as it can cause errors for any tasks with validation and resync enabled.
AWS DMS が移行精度を向上させるために Data Resync を導入 - AWS
今回のデータ移行では、絵文字のカラムが差分として認識される事象が発生しました。片方は絵文字に見えているのに対して、もう片方では「?」となっており差分として判定されていました。AWS DMS の設定変更で解消できれば良かったのですが原因は特定できなかったため、移行前後のデータを手動で突き合わせてデータが一致することを確認しました。
その他の注意点としては、primary key や unique key が含まれないテーブルや primary key のデータ型によってはデータバリデーション機能の対象外となるので、移行対象のテーブルでデータバリデーション機能が想定通り動作しているかどうか事前に確認しておきましょう。
AWS DMS data validation - AWS Database Migration Service
Data validation requires that the table has a primary key or unique index. Primary key columns cannot be of type CLOB, BLOB, BINARY, or BYTE. For primary key columns of type VARCHAR or CHAR, the length must be less than 1024. You must specify the length in the datatype. You can't use unbounded data types as a primary key for data validation.
AWS DMS 関連のコンポーネントの管理
Replication Instance、Replication Task などの データ移行で利用する AWS リソースは Terraform で管理していました。環境の作り直しも容易で設定値のレビューもしやすいため、何かしらの IaC ツールで管理することをお勧めします。今回のデータ移行では、最小限のダミーデータを利用して作成した AWS リソースの動作確認をした上で、実際の DB のデータを使ったデータ移行の検証を行いました。
Replication Instance のサイジング
Replication Instance の構築にあたっては、移行対象のデータサイズやデータ移行にかかる時間、コストも踏まえて最適な instance type に調整する必要がありました。その際には、下記の AWS のドキュメントを参考にしつつ、本番環境の DB Snapshot を利用したデータ移行の検証を複数回行い、CPUUtilization などのメトリックの推移やデータ移行にかかった時間を基に調整していました。
Choosing the right AWS DMS replication instance for your migration - AWS Database Migration Service
今回のデータ移行では検証時間がなく採用できなかったのですが、Replication Instance が不要で pay-for-use の費用モデルでコストをある程度抑えやすい DMS Serverless を利用するという選択肢もあるでしょう。
Working with AWS DMS Serverless - AWS Database Migration Service
終わりに
AWS DMS を利用したデータ移行を実施し、大きなトラブルなく完了することができました。
今回のデータ移行を通じて、事前準備の重要性を改めて実感しました。特に、AWS 公式ドキュメントの熟読、移行先 DB のスキーマの事前定義、継続的な動作検証といった準備段階での取り組みが、データ移行メンテナンスの実施に大きく寄与したと考えています。
また、データ移行にあたっては下記の記事・登壇資料も参考にさせていただきました。この場をお借りして、感謝申し上げます。
AWS DMS は異なる RDBMS 間でのデータ移行を効率的に行える優れたサービスですが、本記事で紹介したような注意点を把握した上で利用することが重要です。この記事が AWS DMS でのデータ移行を検討されている方の参考になれば幸いです。次回の SRE 連載もお楽しみに!