DynamoDB から Spanner への移行

このチュートリアルでは、Amazon DynamoDB から Spanner に移行する方法について説明します。このチュートリアルは主に、NoSQL システムから Spanner への移行を考えているアプリ所有者を対象としています。Spanner は完全にリレーショナルでフォールト トレラント、かつスケーラビリティに優れた SQL データベース システムであり、トランザクションをサポートしています。データ型とレイアウトの点で Amazon DynamoDB テーブルの使い方が一定であれば Spanner へのマッピングは難しくありません。Amazon DynamoDB テーブルに含まれているデータ型や値が限定されていない場合は、DatastoreFirestore など、他の NoSQL サービスに移行するほうが簡単かもしれません。

このチュートリアルでは、データベース スキーマ、データ型、NoSQL の基本、リレーショナル データベース システムについての知識があることを前提としています。このチュートリアルでは主に、定義済みのタスクを実行して移行を行ってみます。チュートリアルの終了後は、提示されたコードや手順を環境に合わせて変更できます。

次のアーキテクチャ図は、このチュートリアルでデータの移行に使用するコンポーネントの概要を示しています。

移行コンポーネントのアーキテクチャ図

目標

  • Amazon DynamoDB から Spanner にデータを移行する。
  • Spanner データベースおよび移行テーブルを作成する。
  • NoSQL スキーマをリレーショナル スキーマにマッピングする。
  • Amazon DynamoDB を使用するサンプル データセットを作成しエクスポートする。
  • Amazon S3 と Cloud Storage の間でデータを転送する。
  • Dataflow を使用して Spanner にデータをロードする。

費用

このチュートリアルでは、課金対象である次の Google Cloudコンポーネントを使用します。

Spanner の請求料金は、インスタンスのコンピューティング容量と毎月の請求期間内に格納されたデータの量に基づいて計算されます。このチュートリアルでは、こうしたリソースを最小限の構成で利用し、最後にクリーンアップします。実際のシナリオでは、スループットとストレージの要件を予測し、Spanner インスタンスのドキュメントを参照して必要なコンピューティング容量を決定します。

このチュートリアルでは、 Google Cloud リソースに加えて、次のアマゾン ウェブ サービス(AWS)リソースも使用します。

  • AWS Lambda
  • Amazon S3
  • Amazon DynamoDB

これらのサービスは移行プロセスにのみ必要になります。チュートリアルの最後に、指示に従ってすべてのリソースをクリーンアップし、不要な料金が発生しないようにしてください。こうした料金の見積もりには、AWS の料金計算ツールを利用します。

料金計算ツールを使うと、予想使用量に基づいて概算費用を計算できます。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Spanner, Pub/Sub, Compute Engine, and Dataflow APIs.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the Spanner, Pub/Sub, Compute Engine, and Dataflow APIs.

    Enable the APIs

  8. このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

    環境を準備する

    このチュートリアルでは、Cloud Shell でコマンドを実行します。Cloud Shell では、 Google Cloudのコマンドラインにアクセスできるほか、 Google Cloud の開発に必要な Google Cloud CLI などのツールも利用できます。Cloud Shell の初期化には数分かかることがあります。

    1. In the Google Cloud console, activate Cloud Shell.

      Activate Cloud Shell

      At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

    2. デフォルトの Compute Engine ゾーンを設定します。たとえば、us-central1-b の場合は、gcloud config set compute/zone us-central1-b を実行します。
    3. サンプルコードを含む GitHub リポジトリのクローンを作成します。git clone https://github.com/GoogleCloudPlatform/dynamodb-spanner-migration.git を実行します。
    4. 次のコマンドを実行して、クローンされたディレクトリに移動します。cd dynamodb-spanner-migration
    5. Python 仮想環境を作成します。pip3 install virtualenv virtualenv env を実行します。
    6. 仮想環境をアクティブにします。source env/bin/activate を実行します。
    7. 必要な Python モジュールをインストールします。pip3 install -r requirements.txt を実行します。

    AWS アクセスを構成する

    このチュートリアルでは、Amazon DynamoDB テーブル、Amazon S3 バケット、その他のリソースを作成して削除します。これらのリソースにアクセスするには、まず必要な AWS Identity and Access Management(IAM)権限を作成する必要があります。テスト アカウントまたはサンドボックス AWS アカウントを使用すれば、同じアカウントで本番環境のリソースに影響を及ぼす心配もありません。

    AWS Lambda の AWS IAM ロールを作成する

    このセクションでは、チュートリアル後半のステップで AWS Lambda が使用する AWS IAM 役割を作成します。

    1. AWS コンソールで、[IAM] セクションに移動し、[Roles] をクリックしてから、[Create role] を選択します。
    2. [Trusted entity type] で、[AWS service] が選択されていることを確認します。
    3. [Use case] で [Lambda] を選択し、[Next] をクリックします。
    4. [Permission policies] フィルタ ボックスに「AWSLambdaDynamoDBExecutionRole」と入力し、Return キーを押して検索します。
    5. [AWSLambdaDynamoDBExecutionRole] チェックボックスをオンにして、[Next] をクリックします。
    6. [Role name] ボックスに「dynamodb-spanner-lambda-role」と入力し、[Create role] をクリックします。

    AWS IAM ユーザーを作成する

    次の手順で、AWS リソースにプログラムでアクセスできる AWS IAM ユーザーを作成します。AWS リソースはこのチュートリアル全体で使用します。

    1. AWS コンソールの [IAM] セクションから、[Users] をクリックし、[Add User] を選択します。
    2. [User name] ボックスに「dynamodb-spanner-migration」と入力します。
    3. [Access type] で、[Access key -Programmatic access] の左側にあるチェックボックスをオンにします。

    4. [Next: Permissions] をクリックします。

    5. [Attach existing policies directly] をクリックし、[Search] ボックスを使用して、次の 3 つのポリシーの横にあるチェックボックスをオンにします。

      • AmazonDynamoDBFullAccess
      • AmazonS3FullAccess
      • AWSLambda_FullAccess
    6. [Next: Tags] と [Next: Review] をクリックしてから、[Create user] をクリックします。

    7. [Show] をクリックして、認証情報を表示します。新しく作成されたユーザーのアクセスキー ID とシークレット アクセスキーが表示されます。次のセクションで認証情報が必要になるため、このウィンドウは開いたままにしておきます。これらの認証情報は安全な場所に保管してください。この情報を使用すればアカウントを改ざんし、環境に影響を与えることが可能になるためです。このチュートリアルの最後に、IAM ユーザーを削除できます。

    AWS コマンドライン インターフェースを構成する

    1. Cloud Shell で、AWS コマンドライン インターフェース(CLI)を構成します。

      aws configure
      

      次の出力が表示されます。

      AWS Access Key ID [None]: PASTE_YOUR_ACCESS_KEY_ID
      AWS Secret Access Key [None]: PASTE_YOUR_SECRET_ACCESS_KEY
      Default region name [None]: us-west-2
      Default output format [None]:
      
      • 作成した AWS IAM アカウントから、ACCESS KEY IDSECRET ACCESS KEY を入力します。
      • [Default region name] フィールドに「us-west-2」と入力します。他のフィールドはデフォルト値のままにしておきます。
    2. AWS IAM コンソール ウィンドウを閉じます。

    データモデルを理解する

    次のセクションでは、Amazon DynamoDB と Spanner のデータ型、キー、インデックスの類似点および相違点を概説します。

    データ型

    Spanner は GoogleSQL データ型を使用します。次の表は、Amazon DynamoDB のデータ型と Spanner のデータ型の対応を示しています。

    Amazon DynamoDB Spanner
    数値 精度または使用目的に応じて、INT64、FLOAT64、TIMESTAMP、または DATE にマッピングされます。
    文字列 文字列
    ブール値 BOOL
    Null 明示的な型はありません。列には NULL 値を入れることができます。
    バイナリ バイト
    セット 配列
    マップとリスト 構造が一貫しており、テーブルの DDL 構文を使用して記述できる場合は構造体。

    主キー

    Amazon DynamoDB の主キーは一意性を確立するもので、ハッシュキーか、ハッシュキーと範囲キーの組み合わせのいずれかになります。このチュートリアルはまず、主キーがハッシュキーである Amazon DynamoDB テーブルを移行することから始まります。このハッシュキーは Spanner テーブルの主キーになります。後で記載するインターリーブされたテーブルのセクションでは、Amazon DynamoDB テーブルが、ハッシュキーと範囲キーで構成される主キーを使用する状況をモデリングします。

    セカンダリ インデックス

    Amazon DynamoDB と Spanner はいずれも、非主キー属性でのインデックスの作成をサポートしています。Amazon DynamoDB テーブルのセカンダリ インデックスをメモしておきます。このセクションの後半で Spanner テーブルでインデックスを作成する際に使用します。

    サンプル テーブル

    このチュートリアルを効率よく進めるために、次のサンプル テーブルを Amazon DynamoDB から Spanner に移行します。

    Amazon DynamoDB Spanner
    テーブル名 Migration Migration
    主キー "Username" : String "Username" : STRING(1024)
    キーのタイプ ハッシュ なし
    その他のフィールド Zipcode: Number Subscribed: Boolean ReminderDate: String PointsEarned: Number Zipcode: INT64 Subscribed: BOOL ReminderDate: DATE PointsEarned: INT64

    Amazon DynamoDB テーブルを準備する

    次のセクションでは、Amazon DynamoDB のソーステーブルを作成し、そこにデータを追加します。

    1. Cloud Shell で、サンプル テーブル属性を使用する Amazon DynamoDB テーブルを作成します。

      aws dynamodb create-table --table-name Migration \
          --attribute-definitions AttributeName=Username,AttributeType=S \
          --key-schema AttributeName=Username,KeyType=HASH \
          --provisioned-throughput ReadCapacityUnits=75,WriteCapacityUnits=75
      
    2. テーブルのステータスが ACTIVE であることを確認します。

      aws dynamodb describe-table --table-name Migration \
          --query 'Table.TableStatus'
      
    3. テーブルにサンプルデータを追加します。

      python3 make-fake-data.py --table Migration --items 25000
      

    Spanner データベースを作成する

    可能な限り最小のコンピューティング容量(100 処理単位)で Spanner インスタンスを作成します。このチュートリアルの範囲では、このコンピューティング容量で十分です。本番環境の場合は、Spanner インスタンスのドキュメントを参照して、データベースのパフォーマンス要件を満たす適切なコンピューティング容量を決定してください。

    この例では、データベースと同時にテーブル スキーマを作成します。データベースを作成した後は、スキーマの更新を行うことも可能であり一般的です。

    1. デフォルトの Compute Engine ゾーンを設定した同じリージョンに Spanner インスタンスを作成します。例: us-central1

      gcloud beta spanner instances create spanner-migration \
          --config=regional-us-central1 --processing-units=100 \
          --description="Migration Demo"
      
    2. Spanner インスタンスにサンプル テーブルとともにデータベースを作成します。

      gcloud spanner databases create migrationdb \
          --instance=spanner-migration \
          --ddl "CREATE TABLE Migration ( \
                  Username STRING(1024) NOT NULL, \
                  PointsEarned INT64, \
                  ReminderDate DATE, \
                  Subscribed BOOL, \
                  Zipcode INT64, \
               ) PRIMARY KEY (Username)"
      

    移行を準備する

    次のセクションでは、Amazon DynamoDB ソーステーブルをエクスポートし、Pub/Sub レプリケーションを設定して、エクスポート中に発生したデータベースへの変更を取得する方法について説明します。

    変更を Pub/Sub にストリーミングする

    データベースの変更を Pub/Sub にストリーミングするには、AWS Lambda 関数を使用します。

    1. Cloud Shell で、ソーステーブルでの Amazon DynamoDB ストリームを有効にします。

      aws dynamodb update-table --table-name Migration \
          --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
      
    2. 変更を受け取るための Pub/Sub トピックを設定します。

      gcloud pubsub topics create spanner-migration
      

      次の出力が表示されます。

      Created topic [projects/your-project/topics/spanner-migration].
      
    3. テーブルの更新を Pub/Sub トピックに push する IAM サービス アカウントを作成します。

      gcloud iam service-accounts create spanner-migration \
          --display-name="Spanner Migration"
      

      次の出力が表示されます。

      Created service account [spanner-migration].
      
    4. IAM ポリシー バインディングを作成して、サービス アカウントに Pub/Sub に公開する権限を持つようにします。GOOGLE_CLOUD_PROJECT は、実際の Google Cloud プロジェクト名で置き換えます。

      gcloud projects add-iam-policy-binding GOOGLE_CLOUD_PROJECT \
          --role roles/pubsub.publisher \
          --member serviceAccount:spanner-migration@GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
      

      次の出力が表示されます。

      bindings:
      (...truncated...)
      - members:
        - serviceAccount:spanner-migration@solution-z.iam.gserviceaccount.com
        role: roles/pubsub.publisher
      
    5. サービス アカウントの認証情報を作成します。

      gcloud iam service-accounts keys create credentials.json \
          --iam-account spanner-migration@GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
      

      次の出力が表示されます。

      created key [5e559d9f6bd8293da31b472d85a233a3fd9b381c] of type [json] as [credentials.json] for [spanner-migration@your-project.iam.gserviceaccount.com]
      
    6. AWS Lambda 関数を準備しパッケージ化して、Amazon DynamoDB テーブルの変更を Pub/Sub トピックに push します。

      pip3 install --ignore-installed --target=lambda-deps google-cloud-pubsub
      cd lambda-deps; zip -r9 ../pubsub-lambda.zip *; cd -
      zip -g pubsub-lambda.zip ddbpubsub.py
    7. 前に作成した Lambda 実行の役割の Amazon Resource Name(ARN)を取得する変数を作成します。

      LAMBDA_ROLE=$(aws iam list-roles \
          --query 'Roles[?RoleName==`dynamodb-spanner-lambda-role`].[Arn]' \
          --output text)
      
    8. pubsub-lambda.zip パッケージを使用して、AWS Lambda 関数を作成します。

      aws lambda create-function --function-name dynamodb-spanner-lambda \
          --runtime python3.9 --role ${LAMBDA_ROLE} \
          --handler ddbpubsub.lambda_handler --zip fileb://pubsub-lambda.zip \
          --environment Variables="{SVCACCT=$(base64 -w 0 credentials.json),PROJECT=GOOGLE_CLOUD_PROJECT,TOPIC=spanner-migration}"
      

      次の出力が表示されます。

      {
          "FunctionName": "dynamodb-spanner-lambda",
          "LastModified": "2022-03-17T23:45:26.445+0000",
          "RevisionId": "e58e8408-cd3a-4155-a184-4efc0da80bfb",
          "MemorySize": 128,
      ... truncated output... "PackageType": "Zip", "Architectures": [ "x86_64" ] }

    9. Create a variable to capture the ARN of the Amazon DynamoDB stream for your table.

      STREAMARN=$(aws dynamodb describe-table \
          --table-name Migration \
          --query "Table.LatestStreamArn" \
          --output text)
      
    10. Lambda 関数を Amazon DynamoDB テーブルに関連付けます。

      aws lambda create-event-source-mapping --event-source ${STREAMARN} \
          --function-name dynamodb-spanner-lambda --enabled \
          --starting-position TRIM_HORIZON
      
    11. テスト中の応答性を最適化するには、前のコマンドの末尾に --batch-size 1 を追加します。こうするとアイテムを作成、更新、または削除するたびに関数がトリガーされます。

      出力は次のようになります。

      {
          "UUID": "44e4c2bf-493a-4ba2-9859-cde0ae5c5e92",
          "StateTransitionReason": "User action",
          "LastModified": 1530662205.549,
          "BatchSize": 100,
          "EventSourceArn": "arn:aws:dynamodb:us-west-2:accountid:table/Migration/stream/2018-07-03T15:09:57.725",
          "FunctionArn": "arn:aws:lambda:us-west-2:accountid:function:dynamodb-spanner-lambda",
          "State": "Creating",
          "LastProcessingResult": "No records processed"
      ... truncated output...
      

    Amazon DynamoDB テーブルを Amazon S3 にエクスポートする

    1. Cloud Shell で、以降の複数のセクションで使用するバケット名の変数を作成します。

      BUCKET=${DEVSHELL_PROJECT_ID}-dynamodb-spanner-export
      
    2. DynamoDB エクスポートを受け取る Amazon S3 バケットを作成します。

      aws s3 mb s3://${BUCKET}
      
    3. AWS Management Console で、[DynamoDB] に移動し、[Tables] をクリックします。

    4. Migration テーブルをクリックします。

    5. [Exports and stream] タブで [Export to S3] をクリックします。

    6. プロンプトが表示されたら、point-in-time-recovery(PITR)を有効にします。

    7. [Browse S3] をクリックして、以前に作成した S3 バケットを選択します。

    8. [Export] をクリックします。

    9. 更新アイコンをクリックして、エクスポート ジョブのステータスを更新します。ジョブのエクスポートが完了するまで数分かかります。

      プロセスが終了したら、出力バケットを確認します。

      aws s3 ls --recursive s3://${BUCKET}
      

      この処理には 5 分ほどかかります。完了すると、次のような出力が表示されます。

      2022-02-17 04:41:46          0 AWSDynamoDB/01645072900758-ee1232a3/_started
      2022-02-17 04:46:04     500441 AWSDynamoDB/01645072900758-ee1232a3/data/xygt7i2gje4w7jtdw5652s43pa.json.gz
      2022-02-17 04:46:17        199 AWSDynamoDB/01645072900758-ee1232a3/manifest-files.json
      2022-02-17 04:46:17         24 AWSDynamoDB/01645072900758-ee1232a3/manifest-files.md5
      2022-02-17 04:46:17        639 AWSDynamoDB/01645072900758-ee1232a3/manifest-summary.json
      2022-02-17 04:46:18         24 AWSDynamoDB/01645072900758-ee1232a3/manifest-summary.md5
      

    移行を実行する

    Pub/Sub 配信が開始されたため、エクスポート後に発生したテーブルの変更をすべて push できます。

    エクスポートしたテーブルを Cloud Storage にコピーする

    1. Cloud Shell で、Amazon S3 からエクスポートされたファイルを受信する Cloud Storage バケットを作成します。

      gcloud storage buckets create gs://${BUCKET}
      
    2. Amazon S3 から受信したファイルを Cloud Storage に同期します。ほとんどのコピー オペレーションには、rsync コマンドが有効です。エクスポート ファイルが大きい(数 GB 以上の)場合は、Cloud Storage Transfer Service を使用して、バックグラウンド転送を管理します。

      gcloud storage rsync s3://${BUCKET} gs://${BUCKET} --recursive --delete-unmatched-destination-objects
      

    データを一括インポートする

    1. エクスポートされたファイルのデータを Spanner テーブルに書き込むには、サンプルの Apache Beam コードを使用して Dataflow ジョブを実行します。

      cd dataflow
      mvn compile
      mvn exec:java \
      -Dexec.mainClass=com.example.spanner_migration.SpannerBulkWrite \
      -Pdataflow-runner \
      -Dexec.args="--project=GOOGLE_CLOUD_PROJECT \
                   --instanceId=spanner-migration \
                   --databaseId=migrationdb \
                   --table=Migration \
                   --importBucket=$BUCKET \
                   --runner=DataflowRunner \
                   --region=us-central1"
      
      1. インポート ジョブの進行状況を確認するには、 Google Cloud コンソールで Dataflow に移動します。

        Dataflow に移動

      2. ジョブの実行中、実行グラフを表示してログを検討できます。[Status] が [Running] と表示されているジョブをクリックします。

        インポート ジョブの実行

    2. 各ステージをクリックすると、処理済みの要素の数が表示されます。すべてのステージが [Succeeded] になると、インポートは完了です。Amazon DynamoDB テーブルで作成された要素と同じ数の要素が、各ステージで処理済みと表示されます。

      インポート ジョブの成功のステージ

    3. 宛先 Spanner テーブルのレコード数が Amazon DynamoDB テーブルの項目数と一致していることを確認します。

      aws dynamodb describe-table --table-name Migration --query Table.ItemCount
      gcloud spanner databases execute-sql migrationdb \ --instance=spanner-migration --sql="select count(*) from Migration"

      次の出力が表示されます。

      $ aws dynamodb describe-table --table-name Migration --query Table.ItemCount
      25000
      $ gcloud spanner databases execute-sql migrationdb --instance=spanner-migration --sql="select count(*) from Migration"
      25000
      
    4. 各テーブルのランダムなエントリをサンプリングして、データが一貫していることを確認します。

      gcloud spanner databases execute-sql migrationdb \
          --instance=spanner-migration \
          --sql="select * from Migration limit 1"
      

      次の出力が表示されます。

       Username: aadams4495
       PointsEarned: 5247
       ReminderDate: 2022-03-14
       Subscribed: True
       Zipcode: 58057
      
    5. 前の手順の Spanner クエリで返されたものと同じ Username を使用して、Amazon DynamoDB テーブルに対するクエリを実行します。たとえば、aallen2538 のようにします。値は、データベースのサンプルデータに固有のものです。

      aws dynamodb get-item --table-name Migration \
          --key '{"Username": {"S": "aadams4495"}}'
      

      他のフィールドの値は、Spanner 出力の値と一致する必要があります。次の出力が表示されます。

      {
          "Item": {
              "Username": {
                  "S": "aadams4495"
              },
              "ReminderDate": {
                  "S": "2018-06-18"
              },
              "PointsEarned": {
                  "N": "1606"
              },
              "Zipcode": {
                  "N": "17303"
              },
              "Subscribed": {
                  "BOOL": false
              }
          }
      }
      

    新しい変更をレプリケートする

    一括インポート ジョブが完了したら、ストリーミング ジョブを設定して、進行中の更新をソーステーブルから Spanner に書き込みます。Pub/Sub のイベントに登録し、それを Spanner に書き込みます。

    作成した Lambda 関数は、ソース Amazon DynamoDB テーブルへの変更を取得し、それを Pub/Sub に公開するよう構成されています。

    1. AWS Lambda がイベントを送信する宛先となる Pub/Sub トピックのサブスクリプションを作成します。

      gcloud pubsub subscriptions create spanner-migration \
          --topic spanner-migration
      

      次の出力が表示されます。

      Created subscription [projects/your-project/subscriptions/spanner-migration].
      
    2. Pub/Sub に入ってくる変更をストリーミングして Spanner テーブルに書き込むには、Cloud Shell から Dataflow ジョブを実行します。

      mvn exec:java \
      -Dexec.mainClass=com.example.spanner_migration.SpannerStreamingWrite \
      -Pdataflow-runner \
      -Dexec.args="--project=GOOGLE_CLOUD_PROJECT \
                   --instanceId=spanner-migration \
                   --databaseId=migrationdb \
                   --table=Migration \
                   --experiments=allow_non_updatable_job \
      --subscription=projects/GOOGLE_CLOUD_PROJECT/subscriptions/spanner-migration \
      --runner=DataflowRunner \
      --region=us-central1"
      
      1. ジョブの進行状況を確認するには、一括読み込みの手順と同様に、 Google Cloud コンソールで Dataflow に移動します。

        Dataflow に移動

      2. [ステータス] が「実行中」のジョブをクリックします。

        ジョブの実行

        処理グラフには前と同様の出力が表示されますが、処理済みの各項目がステータス ウィンドウでカウントされます。システムの遅延時間は、Spanner テーブルに変更が反映されるまでに生じると思われる遅延の大まかな予想です。

        遅延時間によるプロセスの実行

    一括読み込みフェーズで実行した Dataflow ジョブは、制限付きデータセットとも呼ばれる一連の有限の入力でした。この Dataflow ジョブは、Pub/Sub をストリーミング ソースとして使用しており、制限なしとみなされます。この 2 種類のソースの詳細については、Apache Beam プログラミング ガイドの PCollection のセクションを参照してください。このステップの Dataflow ジョブはアクティブ状態が維持されます。完了しても停止しません。ストリーミング Dataflow ジョブのステータスは、「成功」ではなく「実行中」のままになります。

    レプリケーションを検証する

    ソーステーブルになんらかの変更を加えて、その変更が Spanner テーブルにレプリケートされることを確認します。

    1. Spanner で存在しない行を照会します。

      gcloud spanner databases execute-sql migrationdb \
          --instance=spanner-migration \
          --sql="SELECT * FROM Migration WHERE Username='my-test-username'"
      

      結果は返されません。

    2. Spanner のクエリで使用したのと同じキーを使用して、Amazon DynamoDB にレコードを作成します。コマンドが正常に実行された場合、出力は生成されません。

      aws dynamodb put-item \
          --table-name Migration \
          --item '{"Username" : {"S" : "my-test-username"}, "Subscribed" : {"BOOL" : false}}'
      
    3. 同じクエリを再度実行して、その行が Spanner に存在することを確認します。

      gcloud spanner databases execute-sql migrationdb \
          --instance=spanner-migration \
          --sql="SELECT * FROM Migration WHERE Username='my-test-username'"
      

      出力には挿入された行が表示されます。

      Username: my-test-username
      PointsEarned: None
      ReminderDate: None
      Subscribed: False
      Zipcode:
      
    4. 元の項目の一部の属性を変更し、Amazon DynamoDB テーブルを更新します。

      aws dynamodb update-item \
          --table-name Migration \
          --key '{"Username": {"S":"my-test-username"}}' \
          --update-expression "SET PointsEarned = :pts, Subscribed = :sub" \
          --expression-attribute-values '{":pts": {"N":"4500"}, ":sub": {"BOOL":true}}'\
          --return-values ALL_NEW
      

      出力は次のようになります。

      {
          "Attributes": {
              "Username": {
                  "S": "my-test-username"
              },
              "PointsEarned": {
                  "N": "4500"
              },
              "Subscribed": {
                  "BOOL": true
              }
          }
      }
      
    5. 変更が Spanner テーブルに伝播されていることを確認します。

      gcloud spanner databases execute-sql migrationdb \
          --instance=spanner-migration \
          --sql="SELECT * FROM Migration WHERE Username='my-test-username'"
      

      出力は次のように表示されます。

      Username          PointsEarned  ReminderDate  Subscribed  Zipcode
      my-test-username  4500          None          True
      
    6. Amazon DynamoDB のソーステーブルからテスト項目を削除します。

      aws dynamodb delete-item \
          --table-name Migration \
          --key '{"Username": {"S":"my-test-username"}}'
      
    7. 対応する行が Spanner テーブルから削除されていることを確認します。変更が伝播されると、次のコマンドはゼロ行を返します。

      gcloud spanner databases execute-sql migrationdb \
          --instance=spanner-migration \
          --sql="SELECT * FROM Migration WHERE Username='my-test-username'"
      

    インターリーブ テーブルを使用する

    Spanner は、テーブルのインターリーブのコンセプトをサポートしています。これはトップレベルの項目に、そのトップレベル項目に関連する複数のネストされた項目があるという設計モデルです(お客様とその注文、プレーヤーとそのゲームスコアなど)。Amazon DynamoDB ソーステーブルで、ハッシュキーと範囲キーで構成される主キーを使用する場合は、次の図のように、インターリーブ テーブルのスキーマをモデリングできます。この構造では親テーブルのフィールドを結合しながら、インターリーブ テーブルを効率的に照会できます。

    ユーザー テーブルと注文テーブルの比較

    セカンダリ インデックスを適用する

    データを読み込んだ後にセカンダリ インデックスを Spanner テーブルに適用することは、ベスト プラクティスの一つです。レプリケーションはすでに機能しているため、セカンダリ インデックスを設定してクエリを高速化します。Spanner のセカンダリ インデックスは、Spanner テーブルと同様、完全整合性を備えています。ただし、多くの NoSQL データベースで一般的な結果整合性とは異なります。この機能はアプリの設計を簡素化するうえで役立ちます。

    インデックスを使用しないクエリを実行します。ここでは特定の列の値を指定して、上位 N 個のオカレンスを探します。これは Amazon DynamoDB における、データベースの効率性を高めるための一般的なクエリです。

    1. Spanner に移動します。

      Spanner に移動

    2. [Spanner Studio] をクリックします。

      [クエリ] ボタン

    3. [Query] フィールドに次のクエリを入力し、[Run query] をクリックします。

      SELECT Username,PointsEarned
        FROM Migration
       WHERE Subscribed=true
         AND ReminderDate > DATE_SUB(DATE(current_timestamp()), INTERVAL 14 DAY)
       ORDER BY ReminderDate DESC
       LIMIT 10
      

      クエリが実行されたら、[Explanation] をクリックして、[Rows scanned] と [Rows returned] をメモします。インデックスがない場合、Spanner はテーブル全体をスキャンして、クエリに一致するデータの小さなサブセットを返します。

      スキャンされた行数と返された行数の比較

    4. これが一般的に発生するクエリを表している場合は、Subscribed 列と ReminderDate 列に複合インデックスを作成します。Spanner コンソールの左側のナビゲーション ペインで [インデックス] を選択し、[インデックスを作成] をクリックします。

    5. テキスト ボックスにインデックスの定義を入力します。

      CREATE INDEX SubscribedDateDesc
      ON Migration (
        Subscribed,
        ReminderDate DESC
      )
      
    6. バックグラウンドでのデータベース構築を開始するには、[作成] をクリックします。

      進行中のスキーマ更新

    7. インデックスが作成されたら、再度クエリを実行して、インデックスを追加します。

      SELECT Username,PointsEarned
        FROM Migration@{FORCE_INDEX=SubscribedDateDesc}
       WHERE Subscribed=true
         AND ReminderDate > DATE_SUB(DATE(current_timestamp()), INTERVAL 14 DAY)
       ORDER BY ReminderDate DESC
       LIMIT 10
      

      クエリの説明をもう一度確認します。[Rows scanned] の数が減っていることを確認してください。各ステップで返される [Rows returned] は、クエリによって返される数と一致します。

      クエリの説明

    インターリーブされたインデックス

    Spanner ではインターリーブされたインデックスを設定できます。前のセクションで説明したセカンダリ インデックスは、データベース階層のルートにあり、従来のデータベースと同じ方法でインデックスを使用します。インターリーブされたインデックスは、インターリーブされた行のコンテキスト内にあります。インターリーブされたインデックスを適用する場所の詳細については、インデックス オプションをご覧ください。

    データモデルに合わせて調整する

    このチュートリアルの移行部分を自分の状況に適応させるには、Apache Beam のソースファイルを変更してください。実際の移行期間中には、ソーススキーマを変更しないようにしてください。そうでないと、データが失われる可能性があります。

    1. 受信 JSON を解析してミューテーションを構築するには、GSON を使用します。JSON 定義はデータに合わせて調整します。

      public static class Record implements Serializable {
      
        private Item Item;
      
      }
      
      public static class Item implements Serializable {
      
        private Username Username;
        private PointsEarned PointsEarned;
        private Subscribed Subscribed;
        private ReminderDate ReminderDate;
        private Zipcode Zipcode;
      
      }
      
      public static class Username implements Serializable {
      
        private String S;
      
      }
      
      public static class PointsEarned implements Serializable {
      
        private String N;
      
      }
      
      public static class Subscribed implements Serializable {
      
        private String BOOL;
      
      }
      
      public static class ReminderDate implements Serializable {
      
        private String S;
      
      }
      
      public static class Zipcode implements Serializable {
      
        private String N;
      
      }
    2. 対応する JSON マッピングを調整します。

      mutation.set("Username").to(record.Item.Username.S);
      
      Optional.ofNullable(record.Item.Zipcode).ifPresent(x -> {
        mutation.set("Zipcode").to(Integer.parseInt(x.N));
      });
      
      Optional.ofNullable(record.Item.Subscribed).ifPresent(x -> {
        mutation.set("Subscribed").to(Boolean.parseBoolean(x.BOOL));
      });
      
      Optional.ofNullable(record.Item.ReminderDate).ifPresent(x -> {
        mutation.set("ReminderDate").to(Date.parseDate(x.S));
      });
      
      Optional.ofNullable(record.Item.PointsEarned).ifPresent(x -> {
        mutation.set("PointsEarned").to(Integer.parseInt(x.N));
      });

    前の手順では、Apache Beam のソースコードを一括インポート用に変更しました。次に同様の方法で、パイプラインのストリーミング部分のソースコードを変更します。最後に、Spanner ターゲット データベースのテーブル作成スクリプト、スキーマ、およびインデックスを調整します。

    クリーンアップ

    このチュートリアルで使用したリソースについて、 Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

    プロジェクトを削除する

    1. In the Google Cloud console, go to the Manage resources page.

      Go to Manage resources

    2. In the project list, select the project that you want to delete, and then click Delete.
    3. In the dialog, type the project ID, and then click Shut down to delete the project.

    AWS リソースを削除する

    このチュートリアル以外で AWS アカウントを使用する場合、次のリソースを削除する際は慎重に行ってください。

    1. Migration という名前の DynamoDB テーブルを削除します。
    2. 移行手順で作成した Amazon S3 バケットLambda 関数を削除します。
    3. 最後に、このチュートリアルで作成した AWS IAM ユーザーを削除します。

    次のステップ