💡

[AWS]AWS DMS で Aurora MySQL を S3 にデータ移行

2023/03/08に公開

この記事の目的

  • 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

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 or Parquet で選択可能
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
  • 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バケット先に評価レポートが作成されます
  • 評価作成完了

    • 評価のリンク先にはテーブル毎の評価結果が一覧表示されます

  • 移行前評価を行うことでより確実に移行タスクの実行が可能になります
株式会社THIRD エンジニアブログ

Discussion