booklista tech blog

booklista のエンジニアリングに関する情報を公開しています。

Reader StoreでAWSアカウント間でのデータ同期をしてみた

こんにちは。プロダクト開発部でクラウドインフラエンジニアとして業務を行っている饂飩です。

今回は、「Reader Store(運営:株式会社ソニー・ミュージックエンタテインメント)」の新しい環境を構築した際に発生したAWSアカウント間でのデータ同期についてお伝えします。

新環境検討の背景

新環境検討のきっかけとなった背景としては以下があります。

  • 大きな開発案件では開発や事業部など全体の部署で成果物がどのようなものか認識を合わせるための環境が欲しい。という要望が上がった
  • 検証環境などでは開発者のテストデータや古い作品のデータが多くストアとしてのイメージがつきにくく認識を合わせることが難しくなっていた

今後システム改善をしていく上でも、事業部全体で認識合わせながら進めることが必須事項になってくることもあり、本番相当のデータで可能な環境を用意する運びとなった。

データ同期をどう行うか

弊社のAWSは商用と開発検証でアカウントが異なるため、アカウントを跨いでデータを同期する必要がありました。
大きく以下2つをどうにかする必要がありました。

1. RDS

候補として以下がありました。

export/importはデータ量がそれなりにありデータ同期するとなるとリードタイムがかかってしまうため不採用にしました。
バイナリログレプリケーションはお試し構築で実施していたため最有力候補でした。
ただ、テーブルを絞った上でデータ同期をするため、今後同期するテーブルが増えることを想定して容易に対応できるようにするためDMSを採用しました。

2. S3

候補として以下がありました。

S3レプリケーションは前提条件でバケットのバージョニングを有効にしなければならず、システム影響調査および環境差異が発生してしまうため不採用にしました。
awscliは処理時間がかかってしまうため不採用にしました。
1h程度でデータ同期が完了したのでDataSyncを採用しました。

構築の流れ

今回私が対応した流れとしては以下となります。

RDSおよびS3の同期設定以外

以前のブログで記載しましたが、Terraformコードがあるので、環境設定だけ追加をしてterraform applyを実施するだけなのですぐ完了しました。

RDS

RDSはDMSでレプリケートしますが、初期はソースDBのスナップショットから復元しました。
以下はDMSを利用したデータ同期を行うために実施した作業内容となります。

データ同期を行う環境構成としては以下のイメージのような形となります。
図のaccount-Aが商用のAWSアカウント、account-Bが開発検証用のAWSアカウントとなります。

AWS/DMS

ネットワーク周り

まずはソースDBが別アカウントに存在していたためVPC PeeringでVPC間通信できるようにしました。
その後Route TableやSecurityGroupの設定を実施しました。

DMS

次にDMS環境構築をしました。
実施した内容としては以下の通りとなります。

  • レプリケーションインスタンスの作成
    レプリケーションタスクが動作するインスタンスを作成しました。

  • ソース/ターゲットエンドポイントの作成
    ソースエンドポイント(移行元RDS接続情報)、ターゲットエンドポイント(移行先RDS接続情報)を作成しました。

  • 移行タスクの作成
    上記で作成したレプリケーションインスタンスとソース/ターゲットエンドポイントを紐付けてデータを移行するタスクを作成しました。

S3

S3は空のバケットを最初に作成しました。
DataSyncで実施した内容としては以下の通りです。

データ同期を行う環境構成としては以下のイメージのような形となります。
図のaccount-Aが商用のAWSアカウント、account-Bが開発検証用のAWSアカウントとなります。

AWS/DataSync

DataSync用のIAMロール作成

DataSyncからS3アクセスできるようにIAMロールを作成しました。
ロールに付与したポリシーは以下のような形になります。

ソース用ポリシーサンプル

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-name"
        },
        {
            "Action": [
                "s3:GetObject",
                "s3:ListMultipartUploadParts",
                "s3:GetObjectTagging",
              ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-name/*"
        }
    ]
}

ターゲット用ポリシーサンプル

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-name"
        },
        {
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:ListMultipartUploadParts",
                "s3:GetObjectTagging",
                "s3:PutObjectTagging",
                "s3:PutObject"
              ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-name/*"
        }
    ]
}

信頼ポリシーサンプル

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {
            "Service": "datasync.amazonaws.com"
        },
        "Action": "sts:AssumeRole",
        "Condition": {
            "StringEquals": {
                "aws:SourceAccount": "account-id"
            },
            "StringLike": {
                "aws:SourceArn": "arn:aws:datasync:region:account-id:*"
            }
        }
    }]
}

S3バケットポリシー修正

先ほど作成したDataSync用のIAMロールでS3アクセスできるようにバケットポリシーを修正しました。

S3バケットポリシーサンプル

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "DataSyncCreateS3LocationAndTaskAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:role/datasync-role"
      },
      "Action": [
        "s3:GetBucketLocation",
        "s3:ListBucket",
        "s3:ListBucketMultipartUploads",
        "s3:AbortMultipartUpload",
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:ListMultipartUploadParts",
        "s3:PutObject",
        "s3:GetObjectTagging",
        "s3:PutObjectTagging"
      ],
      "Resource": [
        "arn:aws:s3:::bucket",
        "arn:aws:s3:::bucket/*"
      ]
    },
    {
      "Sid": "DataSyncCreateS3Location",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:role/datasync-role"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::bucket"
    }
  ]
}

DataSync

次にDataSync環境構築をしました。
実施した内容としては以下の通りとなります。

  • ソース/ターゲットロケーションの作成
    ソースロケーション(移行元S3)、ターゲットロケーション(移行先S3への接続情報)を作成しました。
    ソースロケーションは、アカウントが異なりコンソールからは設定できなかったので、aws cliコマンドを実行しました。
  #aws datasync create-location-s3 \
    --s3-bucket-arn arn:aws:s3:::bucket \
    --s3-config '{
      "BucketAccessRoleArn":"arn:aws:iam::account-id:role/datasync-role"
    }'
  • 移行タスクの作成
    上記で作成したソースロケーションからターゲットロケーションへデータを移行するタスクを作成しました。

データ同期

作成したDMSおよびDataSyncの移行タスクを実行しました。
どちらも初回フル同期して、フル同期後はソース側で変更があれば継続的にレプリケーションする設定となっています。

DMSはタスク実行の際に、ターゲットDB内のテーブルをtruncateして再度ソースDBからフルロードする設定にしているため初回同期は3hほどかかりました。

DataSyncの初回はソースS3の全てのオブジェクトをターゲットS3にコピーするため12hほどかかりました。

直面した課題・反省点

S3関連のコスト面の見積が甘かった

S3上のオブジェクト数からデータ同期する際のDataSync料金(想定データ転送量)を見積りして大したコストにならないとしていました。
だが、移行し始めた翌月のS3コスト(GET、SELECT、他のすべてのリクエスト)が前月差で3倍ほど跳ね上がりました。

原因は、S3同期を毎時やっていたことにありました。
毎時S3オブジェクト同期し、その都度オブジェクト比較するためオブジェクト数2431のリクエストが発生していました。
こちらのコストを下げるべく、同期の頻度を毎時から1日1回に変更することでオブジェクト数*31になり、当初想定していた試算コストくらいになりました。

GuardDutyのコストを見積もっていなかった

GuardDuty S3 Protection機能を有効にしていたのを失念していました。
こちらも移行し始めた翌月のコスト(S3データイベント分析)が前月差30倍ほど跳ね上がりました。

こちらもS3同期頻度を変更することでS3データイベント分析が減ったため前月差2倍程度になりました。

まとめ

今回Reader Storeで新しい環境を構築した件についてお話ししました。
DataSyncを継続的に移行する際にはS3コストにご注意下さい。

新しい環境はまだ未完な状態ではあるので、今後も環境の改善を進めて本番に近い確認ができるようにして、サービスの品質も高めていきたいです。

他にも実施した内容はあるのでどこかでまたお話しできたらと思っています。

以上、読んでいただきありがとうございました。