💡
[AWS]AWS DMS で Aurora MySQL を S3 にデータ移行
この記事の目的
- AWS DMS が何か分かる
- DMSにて Aurora MySQL のデータをS3に移行してみる
AWS DMS
- AWS Database Migration Service
- データベース移行するためのサービス
- RDMS間移行および異種ストレージへの移行もサポートしている
データ移行
- 今回は Aurora MySQL のデータをS3に移行してみる
構成
- ざっくりとした構成は以下となる
- Aurora が存在する同サブネットにDMSのインスタンスを構築する
- DMSインスタンス内でタスクを起動
- エンドポイントを経由してAuroraのデータを取得
- エンドポイントを経由して取得したデータをS3へ転送
構築
- 今回は CloudForamtion を使用してAWSリソースを構築する
- データ移行元である Aurora MySQL は既に構築済みとする
S3
- 意図しないデータアクセスを防ぐため「ブロックパブリックアクセス」をオンにしています
- オブジェクト暗号化(SSE-S3)をオンにしています
ReplicationBucket:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: {バケット名}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags:
- Key: Name
Value: {バケット名}
DMSエンドポイント
Aurora
- DMSがAuroraに接続するためのエンドポイント設定
- ここでは記述していませんが、
Username
/Password
は秘匿情報のため SecretManager から値を取得するようにしています -
ServerName
はAuroraのクラスターエンドポイントを指定します
DMSEndpointToDMS:
Type: AWS::DMS::Endpoint
Properties:
EndpointIdentifier: {エンドポイント名}
DatabaseName: {接続先DB名}
EndpointType: source
EngineName: aurora
Username: {接続先DBの接続ユーザー名}
Password: {接続先DBの接続パスワード}
Port: 3306
ServerName: {接続先DBのドメイン}
Tags:
- Key: Name
Value: !Sub datalake-rds-migrator-rds-to-dms-${Env}
S3
- DMSがS3に接続するためのエンドポイント設定
- エンドポイントがS3へアクセスするための権限が必要でIAMロールを設定
-
TimestampColumnName
- マイグレーションした日時をデータに含めたい場合に指定する
- ここで指定したカラム名でデータに追記される
-
IncludeOpForFullLoad
- マイグレーションが発生したDBへのDMLを記録するか設定
- Insertなら
I
UpdateならU
DeleteならD
がカラム追加される
-
AddColumnName
- CSVヘッダーを追加するかどうかの設定
-
DataFormat
- S3への出力形式を
CSV
orParquet
で選択可能
- S3への出力形式を
DMSEndpointToS3:
Type: AWS::DMS::Endpoint
Properties:
EndpointIdentifier: {エンドポイント名}
EndpointType: target
EngineName: s3
S3Settings:
BucketName: {接続先バケット名}
ServiceAccessRoleArn: {エンドポイント用IAMロールのArn}
TimestampColumnName: timestamp
IncludeOpForFullLoad: true
CompressionType: gzip
DataFormat: csv
MaxFileSize: 10000 # in KB
AddColumnName: true
Tags:
- Key: Name
Value: {接続先バケット名}
IAM
- エンドポイントで使用するIAMロールを定義
- 今回お試しのため S3 のフル権限を付与してますが本当は最小権限付与を推奨
DMSEndpointIAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: {ロール名}
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- dms.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Path: /
DMSサブネットグループ
- DMSインスタンスを配置するサブネットの設定
- サブネットが複数ある場合は
SubnetIds
で複数設定
DMSSubnetGroup:
Type: AWS::DMS::ReplicationSubnetGroup
Properties:
ReplicationSubnetGroupIdentifier: {サブネットグループ名}
SubnetIds:
- {サブネットID}
- {サブネットID}
Tags:
- Key: Name
Value: {サブネットグループ名}
DMSインスタンス
-
AllowMajorVersionUpgrade
- インスタンスに割り当てるストレージサイズ
-
EngineVersion
-
3.4.7
から各種サービスに対してVPCエンドポイントが必要になるので注意 - 3.4.7リリースノート
-
-
MultiAZ
- インスタンスをマルチAZ配置するかどうか
- お試しなので
false
を設定しています
-
ReplicationSubnetGroupIdentifier
- 上記で作成したサブネットグループ名を指定
- ex.
!Ref DMSSubnetGroup
DMSReplicationInstance:
Type: AWS::DMS::ReplicationInstance
Properties:
AllocatedStorage: 50
AllowMajorVersionUpgrade: false
AutoMinorVersionUpgrade: true
EngineVersion: 3.4.6
MultiAZ: false
PreferredMaintenanceWindow: sun:20:00-sun:22:00
PubliclyAccessible: false
ReplicationInstanceClass: dms.t3.small
ReplicationInstanceIdentifier: {インスタンス名}
ReplicationSubnetGroupIdentifier: {サブネットグループ名}
VpcSecurityGroupIds:
- {セキュリティグループID}
Tags:
- Key: Name
Value: {インスタンス名}
DMSタスク
-
CdcStartPosition
- CDC開始する日時を指定
-
MigrationType
- マイグレーションタイプを選択する
- 既存データ一括かCDCか両方か
-
ReplicationTaskSettings
- 最初なにを設定するか全くわからず
- マネジメントコンソールでDMSタスクを作成しその設定をそのまま持ってきた
-
SourceEndpointArn
- 移行元のDMSエンドポイントARNを指定
-
TargetEndpointArn
- 移行先のDMSエンドポイントARNを指定
-
TableMappings
- どのスキーマを移行対象とするかなどの設定
- 指定DB内テーブル全てや特定のテーブルのみなどの設定をする
- 今回はDB内テーブル全てを指定する設定
DMSReplicationTask:
Type: AWS::DMS::ReplicationTask
Properties:
CdcStartPosition: "2020-01-01T00:00:00"
MigrationType: full-load-and-cdc
ReplicationInstanceArn: !Ref DMSReplicationInstance
ReplicationTaskIdentifier: {レプリケーションタスク名}
ReplicationTaskSettings: '{"TargetMetadata":{"TargetSchema":"","SupportLobs":true,"FullLobMode":false,"LobChunkSize":64,"LimitedSizeLobMode":true,"LobMaxSize":32,"InlineLobMaxSize":0,"LoadMaxFileSize":0,"ParallelLoadThreads":0,"ParallelLoadBufferSize":0,"BatchApplyEnabled":false,"TaskRecoveryTableEnabled":false,"ParallelLoadQueuesPerThread":0,"ParallelApplyThreads":0,"ParallelApplyBufferSize":0,"ParallelApplyQueuesPerThread":0},"FullLoadSettings":{"CreatePkAfterFullLoad":false,"StopTaskCachedChangesApplied":false,"StopTaskCachedChangesNotApplied":false,"MaxFullLoadSubTasks":8,"TransactionConsistencyTimeout":600,"CommitRate":10000},"Logging":{"EnableLogging":true,"LogComponents":[{"Id":"SOURCE_UNLOAD","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"SOURCE_CAPTURE","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TARGET_LOAD","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TARGET_APPLY","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TASK_MANAGER","Severity":"LOGGER_SEVERITY_DEFAULT"}],"CloudWatchLogGroup":null,"CloudWatchLogStream":null},"ControlTablesSettings":{"ControlSchema":"","HistoryTimeslotInMinutes":5,"HistoryTableEnabled":false,"SuspendedTablesTableEnabled":false,"StatusTableEnabled":false},"StreamBufferSettings":{"StreamBufferCount":3,"StreamBufferSizeInMB":8,"CtrlStreamBufferSizeInMB":5},"ChangeProcessingDdlHandlingPolicy":{"HandleSourceTableDropped":true,"HandleSourceTableTruncated":true,"HandleSourceTableAltered":true},"ErrorBehavior":{"DataErrorPolicy":"LOG_ERROR","DataTruncationErrorPolicy":"LOG_ERROR","DataErrorEscalationPolicy":"SUSPEND_TABLE","DataErrorEscalationCount":0,"TableErrorPolicy":"SUSPEND_TABLE","TableErrorEscalationPolicy":"STOP_TASK","TableErrorEscalationCount":0,"RecoverableErrorCount":-1,"RecoverableErrorInterval":5,"RecoverableErrorThrottling":true,"RecoverableErrorThrottlingMax":1800,"RecoverableErrorStopRetryAfterThrottlingMax":false,"ApplyErrorDeletePolicy":"IGNORE_RECORD","ApplyErrorInsertPolicy":"LOG_ERROR","ApplyErrorUpdatePolicy":"LOG_ERROR","ApplyErrorEscalationPolicy":"LOG_ERROR","ApplyErrorEscalationCount":0,"ApplyErrorFailOnTruncationDdl":false,"FullLoadIgnoreConflicts":true,"FailOnTransactionConsistencyBreached":false,"FailOnNoTablesCaptured":false},"ChangeProcessingTuning":{"BatchApplyPreserveTransaction":true,"BatchApplyTimeoutMin":1,"BatchApplyTimeoutMax":30,"BatchApplyMemoryLimit":500,"BatchSplitSize":0,"MinTransactionSize":1000,"CommitTimeout":1,"MemoryLimitTotal":1024,"MemoryKeepTime":60,"StatementCacheSize":50},"ValidationSettings":{"EnableValidation":false,"ValidationMode":"ROW_LEVEL","ThreadCount":5,"FailureMaxCount":10000,"TableFailureMaxCount":1000,"HandleCollationDiff":false,"ValidationOnly":false,"RecordFailureDelayLimitInMinutes":0,"SkipLobColumns":false,"ValidationPartialLobSize":0,"ValidationQueryCdcDelaySeconds":0,"PartitionSize":10000},"PostProcessingRules":null,"CharacterSetSettings":null,"LoopbackPreventionSettings":null,"BeforeImageSettings":null}'
SourceEndpointArn: !Ref DMSEndpointToDMS
TableMappings: '{"rules":[{"rule-type":"selection","rule-id":"1","rule-name":"1","object-locator":{"schema-name":"{移行元DB名}","table-name":"%"},"rule-action":"include"}]}'
TargetEndpointArn: !Ref DMSEndpointToS3
Tags:
- Key: Name
Value: {レプリケーションタスク名}
デプロイ
- AWS SAM を使用して上記CloudFormationをデプロイします
- 上記CloudFormation定義を
template.yaml
として配置- 以下にテンプレート全文を記載
template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Resources:
ReplicationBucket:
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: { バケット名 }
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Tags:
- Key: Name
Value: { バケット名 }
DMSEndpointIAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: { ロール名 }
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- dms.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Path: /
DMSSubnetGroup:
Type: AWS::DMS::ReplicationSubnetGroup
Properties:
ReplicationSubnetGroupIdentifier: { サブネットグループ名 }
SubnetIds:
- { サブネットID }
- { サブネットID }
Tags:
- Key: Name
Value: { サブネットグループ名 }
DMSReplicationInstance:
Type: AWS::DMS::ReplicationInstance
Properties:
AllocatedStorage: 50
AllowMajorVersionUpgrade: false
AutoMinorVersionUpgrade: true
EngineVersion: 3.4.6
MultiAZ: false
PreferredMaintenanceWindow: sun:20:00-sun:22:00
PubliclyAccessible: false
ReplicationInstanceClass: dms.t3.small
ReplicationInstanceIdentifier: { インスタンス名 }
ReplicationSubnetGroupIdentifier: { サブネットグループ名 }
VpcSecurityGroupIds:
- { セキュリティグループID }
Tags:
- Key: Name
Value: { インスタンス名 }
DMSReplicationTask:
Type: AWS::DMS::ReplicationTask
Properties:
CdcStartPosition: "2020-01-01T00:00:00"
MigrationType: full-load-and-cdc
ReplicationInstanceArn: !Ref DMSReplicationInstance
ReplicationTaskIdentifier: { レプリケーションタスク名 }
ReplicationTaskSettings: '{"TargetMetadata":{"TargetSchema":"","SupportLobs":true,"FullLobMode":false,"LobChunkSize":64,"LimitedSizeLobMode":true,"LobMaxSize":32,"InlineLobMaxSize":0,"LoadMaxFileSize":0,"ParallelLoadThreads":0,"ParallelLoadBufferSize":0,"BatchApplyEnabled":false,"TaskRecoveryTableEnabled":false,"ParallelLoadQueuesPerThread":0,"ParallelApplyThreads":0,"ParallelApplyBufferSize":0,"ParallelApplyQueuesPerThread":0},"FullLoadSettings":{"CreatePkAfterFullLoad":false,"StopTaskCachedChangesApplied":false,"StopTaskCachedChangesNotApplied":false,"MaxFullLoadSubTasks":8,"TransactionConsistencyTimeout":600,"CommitRate":10000},"Logging":{"EnableLogging":true,"LogComponents":[{"Id":"SOURCE_UNLOAD","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"SOURCE_CAPTURE","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TARGET_LOAD","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TARGET_APPLY","Severity":"LOGGER_SEVERITY_DEFAULT"},{"Id":"TASK_MANAGER","Severity":"LOGGER_SEVERITY_DEFAULT"}],"CloudWatchLogGroup":null,"CloudWatchLogStream":null},"ControlTablesSettings":{"ControlSchema":"","HistoryTimeslotInMinutes":5,"HistoryTableEnabled":false,"SuspendedTablesTableEnabled":false,"StatusTableEnabled":false},"StreamBufferSettings":{"StreamBufferCount":3,"StreamBufferSizeInMB":8,"CtrlStreamBufferSizeInMB":5},"ChangeProcessingDdlHandlingPolicy":{"HandleSourceTableDropped":true,"HandleSourceTableTruncated":true,"HandleSourceTableAltered":true},"ErrorBehavior":{"DataErrorPolicy":"LOG_ERROR","DataTruncationErrorPolicy":"LOG_ERROR","DataErrorEscalationPolicy":"SUSPEND_TABLE","DataErrorEscalationCount":0,"TableErrorPolicy":"SUSPEND_TABLE","TableErrorEscalationPolicy":"STOP_TASK","TableErrorEscalationCount":0,"RecoverableErrorCount":-1,"RecoverableErrorInterval":5,"RecoverableErrorThrottling":true,"RecoverableErrorThrottlingMax":1800,"RecoverableErrorStopRetryAfterThrottlingMax":false,"ApplyErrorDeletePolicy":"IGNORE_RECORD","ApplyErrorInsertPolicy":"LOG_ERROR","ApplyErrorUpdatePolicy":"LOG_ERROR","ApplyErrorEscalationPolicy":"LOG_ERROR","ApplyErrorEscalationCount":0,"ApplyErrorFailOnTruncationDdl":false,"FullLoadIgnoreConflicts":true,"FailOnTransactionConsistencyBreached":false,"FailOnNoTablesCaptured":false},"ChangeProcessingTuning":{"BatchApplyPreserveTransaction":true,"BatchApplyTimeoutMin":1,"BatchApplyTimeoutMax":30,"BatchApplyMemoryLimit":500,"BatchSplitSize":0,"MinTransactionSize":1000,"CommitTimeout":1,"MemoryLimitTotal":1024,"MemoryKeepTime":60,"StatementCacheSize":50},"ValidationSettings":{"EnableValidation":false,"ValidationMode":"ROW_LEVEL","ThreadCount":5,"FailureMaxCount":10000,"TableFailureMaxCount":1000,"HandleCollationDiff":false,"ValidationOnly":false,"RecordFailureDelayLimitInMinutes":0,"SkipLobColumns":false,"ValidationPartialLobSize":0,"ValidationQueryCdcDelaySeconds":0,"PartitionSize":10000},"PostProcessingRules":null,"CharacterSetSettings":null,"LoopbackPreventionSettings":null,"BeforeImageSettings":null}'
SourceEndpointArn: !Ref DMSEndpointToDMS
TableMappings: '{"rules":[{"rule-type":"selection","rule-id":"1","rule-name":"1","object-locator":{"schema-name":"{移行元DB名}","table-name":"%"},"rule-action":"include"}]}'
TargetEndpointArn: !Ref DMSEndpointToS3
Tags:
- Key: Name
Value: { レプリケーションタスク名 }
- 上記
template.yaml
の階層へ移動し以下SAMコマンドを打つ
sam deploy \
--stack-name {CloudFormationスタック名} \
--s3-bucket {テンプレート配置先S3バケット} \
--s3-prefix {S3バケットでのプレフィックス} \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--region {AWS Region} \
--force-upload
-
SAMインストールについては以下参照
-
SAMが成功するとCloudForamtionにスタックが作成され各種リソースが作成される
-
インスタンス
-
エンドポイント
-
タスク
動作確認
エンドポイント接続確認
- Aurora および S3 への接続が正常であるか確認します
S3
- AWSマネジメントコンソールからS3接続用エンドポイントを開く
- 「接続」タブから「接続テスト」ができるのでテスト実行する
- 接続成功するとステータスが「successful」となる
- 接続失敗する場合以下が考えられます
- バケット名が間違っている
- DMSインスタンスのエンジンバージョン
3.4.7
から プライベートサブネットに展開している場合はVPCエンドポイント
が必須となった(3.4.7の3.4.7リリースノート参照) - 付与しているロールにS3の権限が不足している
- 詳細は 公式ドキュメント を参照
Aurora
- テストの仕方はS3同様
- 接続失敗する場合以下が考えられます
- DB名が間違っている
- ユーザー名が間違っている
- パスワードが間違っている
- 接続先ドメインが間違っている
- 詳細は 公式ドキュメント を参照
データマイグレーション
- タスクを実行し Aurora のデータが S3 にマイグレーションされるか確認する
タスク実行
- タスクを開き「アクション」からタスク実行を行います
- 「再起動/再開」が実行にあたります
- 実行が正常に動作すると割とすぐにマイグレーションが始まり完了します
実行確認
- マイグレーションが成功すると「テーブル統計」が更新されます
- どのDBのどのテーブルがどれくらいの時間、どれだけの件数のデータをマイグレーションしたか一覧表示されています
- このように一覧確認できるのは非常に有り難いですね
フルロード確認
- S3側にデータマイグレーションされたことも確認できました
- 初回のフルロードされたデータは
LOAD
がプレフィックスとなります
CDC確認
-
随時Auroraへの変更をキャプチャしてマイグレーションするCDCも確認
-
適当なテーブルに1件データ登録します
-
統計データの「挿入」に1件入っていることが確認できます
-
S3にデータがマイグレーションされていることが確認できます
これで Aurora のデータは常時 S3 にマイグレーションされるように設定できました
DMSは設定がややこしい部分が多いのですが、1度構築できると運用面ではお手製マイグレーションツールより断然楽ができるのでは無いかと実感できました
データマイグレーションの機会はそう多くはありませんが、積極的に活用したいサービスの1つです
移行前評価
- DMSタスクには移行前に事前評価を行える機能が備わっています
- 移行は万能ではなく幾らか制約、制限が設けられています
- その評価を行ってくれるすぐれものです
移行前評価の実行
-
タスクは「停止」している必要があります
-
S3にアクセスするための IAM Role が必要です
-
「移行前評価」タブを開き「移行前評価の作成」を押下します
-
今回はデフォルトのままで実行します
- 基本的に評価対象は全てチェックするで良いかと思います
- IAM Role は事前に作成しておく必要があります
- 指定したS3バケット先に評価レポートが作成されます
-
評価作成完了
- 評価のリンク先にはテーブル毎の評価結果が一覧表示されます
- 移行前評価を行うことでより確実に移行タスクの実行が可能になります
Discussion