DynamoDB에서 Cloud Spanner로 이전

이 가이드에서는 Amazon DynamoDB에서 Spanner로 마이그레이션하는 방법을 설명합니다. 이 가이드는 기본적으로 NoSQL 시스템에서 Spanner로 이전하고자 하는 앱 소유자를 위한 것입니다. Spanner는 트랜잭션을 지원하는 확장성이 뛰어난 완전 관계형 내결함성 SQL 데이터베이스 시스템입니다. 유형과 레이아웃 측면에서 Amazon DynamoDB 테이블을 꾸준히 사용하는 경우 Spanner에 간단하게 매핑할 수 있습니다. Amazon DynamoDB 테이블에 임의 데이터 유형과 값이 포함된 경우에는 Datastore 또는 Firebase와 같은 다른 NoSQL 서비스로 이전하는 것이 더 간단할 수도 있습니다.

이 가이드는 사용자가 데이터베이스 스키마, 데이터 유형, NoSQL의 기본 정보, 관계형 데이터베이스 시스템에 익숙하다고 가정합니다. 이 가이드는 사전 정의된 작업을 실행하여 이전 작업 예시를 수행합니다. 가이드 진행 후에는 제공된 코드 및 단계를 수정하여 사용자 환경에 맞출 수 있습니다.

다음의 아키텍처 다이어그램은 데이터를 마이그레이션하는 가이드에서 사용된 구성요소를 간략하게 보여줍니다.

마이그레이션 구성요소의 아키텍처 다이어그램

목표

  • Amazon DynamoDB에서 Spanner로 데이터를 마이그레이션합니다.
  • Spanner 데이터베이스 및 마이그레이션 테이블을 만듭니다.
  • NoSQL 스키마를 관계형 스키마에 매핑합니다.
  • Amazon DynamoDB를 사용하는 샘플 데이터세트를 만들고 내보냅니다.
  • Amazon S3 및 Cloud Storage 간에 데이터를 전송합니다.
  • Dataflow를 사용하여 데이터를 Spanner에 로드합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

  • GKE
  • Pub/Sub
  • Cloud Storage
  • Dataflow

Spanner 비용은 월별 결제 주기에 저장된 노드 시간 및 데이터 양을 기준으로 청구됩니다. 이 가이드에서는 이러한 리소스의 최소 구성이 사용되며 끝날 때 삭제됩니다. 실제 시나리오의 경우 처리량 및 스토리지 요구사항을 추정한 다음 Spanner 인스턴스 문서를 사용하여 필요한 노드 수를 결정합니다.

이 가이드에서는 Google Cloud 리소스 외에도 다음과 같은 Amazon Web Services(AWS) 리소스를 사용합니다.

  • Amazon EMR
  • AWS Lambda
  • Amazon S3
  • Amazon DynamoDB

이러한 서비스는 이전 프로세스를 진행하는 동안에만 필요합니다. 가이드를 마치면 안내에 따라 모든 리소스를 삭제하여 불필요한 비용 청구를 방지하세요. AWS 가격 계산기를 사용하여 비용을 추산하세요.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  3. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

  4. Spanner, Pub/Sub, Compute Engine, and Dataflow API를 사용 설정합니다.

    API 사용 설정

이 가이드를 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않게 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

환경 준비

이 가이드에서는 Cloud Shell에서 명령어를 실행합니다. Cloud Shell은 Google Cloud의 명령줄에 대한 액세스 권한을 제공하고 Cloud SDK 및 Google Cloud 개발에 필요한 기타 도구를 포함합니다. Cloud Shell은 초기화하는 데 몇 분 정도 걸릴 수 있습니다.

  1. Cloud Shell을 활성화합니다.

    Cloud Shell 활성화

  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 가상 환경을 만듭니다.

    virtualenv --python python2 env
    
  6. 가상 환경을 활성화합니다.

    source env/bin/activate
    
  7. 필수 Python 모듈을 설치합니다.

    pip 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. Choose the service that will use this role(이 역할을 사용할 서비스 선택)에서 Lambda를 클릭한 다음 Next:Permissions(다음: 권한)를 클릭합니다.
  3. Policy Type(정책 유형) 상자에 AWSLambdaDynamoDBExecutionRole을 입력합니다.
  4. AWSLambdaDynamoDBExecutionRole 체크박스를 선택한 다음 Next:Review(다음: 검토)를 클릭합니다.
  5. Role name(역할 이름) 상자에 dynamodb-spanner-lambda-role을 입력한 다음 Create role(역할 만들기)을 클릭합니다.

AWS IAM 사용자 만들기

다음 단계를 따라 이 가이드 전반에서 사용할 AWS 리소스에 대한 프로그래매틱 액세스 권한이 있는 AWS IAM 사용자를 만듭니다.

  1. AWS 콘솔의 IAM 섹션에 있는 상태에서 Users(사용자)를 클릭한 다음 Add User(사용자 추가)를 선택합니다.
  2. User name(사용자 이름) 상자에 dynamodb-spanner-migration을 입력합니다.
  3. Access type(액세스 유형)에서 Programmatic access(프로그래매틱 액세스)를 클릭합니다.

  4. Next: Permissions(다음: 권한)를 클릭합니다.

  5. Attach existing policies directly(기존 정책 직접 연결)을 선택하고 다음의 두 정책을 선택합니다.

    • AmazonDynamoDBFullAccesswithDataPipeline
    • AmazonS3FullAccess
  6. Next: Review(다음: 검토)를 클릭한 다음 Create user(사용자 만들기)를 클릭합니다.

  7. Show(표시)를 클릭하여 사용자 인증 정보를 봅니다. 새로 생성된 사용자의 액세스 키 ID 및 비밀 액세스 키가 표시됩니다. 다음 섹션에서 사용자 인증 정보가 필요하기 때문에 이 창을 열어놓습니다. 이러한 사용자 인증 정보를 안전하게 보관하세요. 사용자 인증 정보가 있으면 계정을 변경하고 사용 환경에 영향을 미칠 수 있습니다. 이 가이드가 끝나면 IAM 사용자를 삭제할 수 있습니다.

AWS 명령줄 인터페이스 구성

  1. Cloud Shell에서 AWS 명령줄 인터페이스(CLI)를 구성합니다.

    aws configure
    

    다음과 같은 출력이 표시됩니다.

    $ 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]:
    user@project:~/dynamodb-spanner$
    
    • 만든 AWS IAM 계정의 ACCESS KEY IDSECRET ACCESS KEY를 입력합니다.
    • 기본 리전 이름 필드에 us-west-2를 입력합니다. 다른 필드는 기본값으로 둡니다.
  2. AWS IAM 콘솔 창을 닫습니다.

데이터 모델 이해

다음 섹션에서는 Amazon DynamoDB 및 Spanner의 데이터 유형, 키, 색인 간 유사점과 차이점을 간략하게 설명합니다.

데이터 유형

Spanner는 표준 SQL 데이터 유형을 사용합니다. 다음 표에서는 Amazon DynamoDB 데이터 유형이 Spanner 데이터 유형에 매핑되는 방식을 설명합니다.

Amazon DynamoDB Spanner
숫자 정밀도나 사용 용도에 따라 INT64, FLOAT64, TIMESTAMP, DATE에 매핑될 수 있습니다.
문자열 문자열
부울 BOOL
Null 명시적인 유형이 없습니다. 열에 null 값이 포함될 수 있습니다.
바이너리 바이트
세트 배열
지도 및 목록 구조가 일관되고 테이블 DDL 구문을 사용하여 설명할 수 있는 경우의 구조체입니다.

기본 키

Amazon DynamoDB 기본 키는 고유성을 설정하며, 해시 키이거나 해시 키와 범위 키의 조합일 수 있습니다. 이 가이드는 기본 키가 해시 키인 Amazon DynamoDB 테이블의 마이그레이션을 모델링하는 것에서 시작됩니다. 이 해시 키는 Spanner 테이블의 기본 키가 됩니다. 나중에 인터리브 처리된 테이블에 관한 섹션에서는 Amazon DynamoDB 테이블이 해시 키와 범위 키로 구성된 기본 키를 사용하는 상황을 모델링합니다.

보조 색인

Amazon DynamoDB와 Spanner 모두 기본 키가 아닌 속성에서 색인을 만드는 것을 지원합니다. 이 가이드의 후반부에서 다루는 Spanner 테이블에서 색인을 만들 수 있도록 Amazon DynamoDB 테이블의 보조 색인을 기록해 두세요.

샘플 테이블

이 가이드를 쉽게 활용하기 위해 다음 샘플 테이블을 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. 샘플 데이터로 테이블을 채웁니다.

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

Spanner 데이터베이스 만들기

이 가이드에서 다루는 범위와 테스트에 적합한 단일 노드 인스턴스를 만듭니다. 프로덕션 배포의 경우 Spanner 인스턴스 문서를 참조하여 데이터베이스 성능 요구사항을 충족하는 적절한 노드 수를 결정합니다.

이 예에서는 테이블 스키마를 데이터베이스와 동시에 만듭니다. 일반적으로 데이터베이스를 만든 후에 스키마 업데이트를 수행할 수 있습니다.

  1. 기본 Compute Engine 영역을 설정한 리전과 동일한 리전에서 Spanner 인스턴스를 만듭니다. 예를 들면 us-central1입니다.

    gcloud spanner instances create spanner-migration \
        --config=regional-us-central1 --nodes=1 \
        --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에 스트림

AWS Lambda 함수를 사용하여 데이터베이스 변경사항을 Pub/Sub에 스트림합니다.

  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
    

    다음과 같은 출력이 표시됩니다.

    $ gcloud pubsub topics create spanner-migration
    Created topic [projects/your-project/topics/spanner-migration].
    
  3. IAM 서비스 계정을 만들어 테이블 업데이트를 Pub/Sub 주제로 푸시합니다.

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

    다음과 같은 출력이 표시됩니다.

    $ gcloud iam service-accounts create spanner-migration --display-name="Spanner Migration"
    Created service account [spanner-migration].
    
  4. 서비스 계정이 Pub/Sub에 게시할 수 있는 권한을 갖도록 IAM 정책 binding을 만듭니다. 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
    

    다음과 같은 출력이 표시됩니다.

    $ 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
    

    다음과 같은 출력이 표시됩니다.

    $ 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 주제로 푸시합니다.

    pip install --ignore-installed --target=lambda-deps google-cloud-pubsub==0.35
    cd lambda-deps; zip -r9 ../pubsub-lambda.zip *; cd -
    zip -g pubsub-lambda.zip ddbpubsub.py
  7. 앞서 만든 Lambda 실행 역할의 Amazon 리소스 이름(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 python2.7 --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}"
    

    다음과 같은 출력이 표시됩니다.

    $ aws lambda create-function --function-name dynamodb-spanner-lambda \
    >   --runtime python2.7 --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": "2018-07-07T12:53:58.670+0000",
        "RevisionId": "e58e8408-cd3a-4155-a184-4efc0da80bfb",
        "MemorySize": 128,
    ... truncated output...
  9. 테이블의 Amazon DynamoDB 스트림 ARN을 캡처할 변수를 만듭니다.

    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을 추가합니다.

    다음과 같은 출력이 표시됩니다.

    $ aws lambda create-event-source-mapping --event-source $STREAMARN \
    >     --function-name dynamodb-spanner-lambda --enabled --starting-position TRIM_HORIZON
    {
        "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"
    }
    

Amazon S3로 Amazon DynamoDB 테이블 내보내기

  1. Cloud Shell에서 여러 후속 섹션에 사용할 버킷 이름의 변수를 만듭니다.

    BUCKET=$DEVSHELL_PROJECT_ID-dynamodb-spanner-export
    
  2. DynamoDB를 내보낼 Amazon S3 버킷을 만듭니다.

    aws s3 mb s3://$BUCKET
    
  3. AWS 관리 콘솔에서 데이터 파이프라인을 클릭합니다.

  4. 새 파이프라인 만들기를 클릭하여 내보내기 작업을 정의합니다.

  5. 이름 필드에 Amazon S3로 내보내기를 입력합니다.

  6. 소스에서 다음을 선택합니다.

    • 템플릿을 사용하여 빌드
    • Amazon S3로 DynamoDB 테이블 내보내기
  7. 매개변수 섹션에서 다음을 정의합니다.

    1. Source DynamoDB table name(소스 DynamoDB 테이블 이름) 필드에 Migration을 입력합니다.
    2. Output S3 folder(출력 S3 폴더) 필드에서 폴더 아이콘을 클릭하고 방금 만든 [Your-Project-ID]-dynamodb-spanner-export Amazon S3 버킷을 선택합니다. 여기서 [YOUR-PROJECT-ID]는 Google Cloud 프로젝트 ID를 나타냅니다.
    3. 내보내기 중에 사용 가능한 모든 읽기 용량을 소비하려면 DynamoDB read throughput ratio(DynamoDB 읽기 처리량 비율) 필드에 1을 입력합니다. 프로덕션 환경에서는 라이브 작업에 지장을 주지 않도록 이 값을 조정합니다.
    4. Region of your DynamoDB table(DynamoDB 테이블 리전) 필드에 리전 이름을 입력합니다(예: us-west-2).
  8. 백업 작업을 즉시 시작하려면 Run(실행)Schedule(일정) 섹션에서 On pipeline activation(파이프라인 활성화 시)을 클릭합니다.

  9. Pipeline Configuration(파이프라인 구성)에서 Logging(로깅) 필드에 Disabled를 입력합니다. 이 가이드를 따라 프로덕션 테이블을 마이그레이션하는 경우에는 이 옵션이 사용 설정된 상태에서 별도의 Amazon S3 버킷을 가리키도록 둡니다. 이렇게 하면 오류를 해결하는 데 도움이 되는 로그를 볼 수 있습니다. 다른 기본 매개변수는 그대로 둡니다.

  10. 백업 프로세스를 시작하려면 활성화를 클릭합니다.

  11. 검증 경고를 확인하라는 메시지가 표시되면 활성화를 클릭합니다. 프로덕션 상황에서는 작업의 최대 기간을 설정하고 로깅을 사용 설정합니다.

  12. 새로고침을 클릭하여 백업 프로세스의 상태를 업데이트합니다. 리소스를 만들고 내보내기를 완료하는 데 몇 분 정도 걸립니다. 프로덕션 환경에서는 더 많은 EMR 리소스를 사용하도록 데이터 파이프라인 작업을 수정하여 이 프로세스의 속도를 높일 수 있습니다.

    프로세스가 완료되면 출력 버킷을 살펴봅니다.

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

    _SUCCESS라는 파일이 있으면 내보내기 작업이 완료된 것입니다.

    $ aws s3 ls --recursive s3://$BUCKET
    
    2018-06-30 13:08:11 3736518 2018-06-30-20-01-21/76b53eea-46d1-4293-ba51-11759f5c65fa
    2018-06-30 13:08:20       0 2018-06-30-20-01-21/_SUCCESS
    2018-06-30 13:08:20     178 2018-06-30-20-01-21/manifest
    

데이터베이스 열기

내보내기 전에 데이터베이스 쓰기 작업을 일시중지했다면 데이터베이스 쓰기를 다시 활성화할 차례입니다. 이제 Pub/Sub가 제공되므로 내보내기 이후에 발생한 테이블 변경사항을 푸시해 전달할 수 있습니다.

내보낸 테이블을 Cloud Storage에 복사

  1. Cloud Shell에서 Cloud Storage 버킷을 만들어 Amazon S3에서 내보낸 파일을 받습니다.

    gsutil mb gs://$BUCKET
    
  2. 파일을 Amazon S3에서 Cloud Storage로 동기화합니다. 대부분의 복사 작업에서는 rsync 명령어가 효과적입니다. 내보내기 파일의 용량이 큰 경우(수 GB 이상) Cloud Storage Transfer Service를 사용하여 백그라운드에서 전송을 관리합니다.

    gsutil rsync -d -r s3://$BUCKET gs://$BUCKET
    

    다음과 같은 출력이 표시됩니다.

    $ gsutil rsync -d -r s3://$BUCKET gs://$BUCKET
    Building synchronization state...
    Starting synchronization...
    Copying s3://project-dynamodb-spanner-export/2018-06-30-20-01-21/76b53eea-46d1-4293-ba51-11759f5c65fa [Content-Type=binary/octet-stream]...
    Copying s3://project-dynamodb-spanner-export/2018-06-30-20-01-21/_SUCCESS [Content-Type=binary/octet-stream]...
    Copying s3://project-dynamodb-spanner-export/2018-06-30-20-01-21/manifest [Content-Type=binary/octet-stream]...
    / [3 files][  3.6 MiB/  3.6 MiB]
    Operation completed over 3 objects/3.6 MiB.
    

데이터 일괄 가져오기

  1. 내보낸 파일의 데이터를 Spanner 테이블에 쓰려면 Dataflow 작업을 샘플 Apache Beam 코드와 함께 실행합니다.

    cd dataflow
    mvn compile
    mvn exec:java \
        -Dexec.mainClass=com.example.spanner_migration.SpannerBulkWrite \
        -Dexec.args="--project=$GOOGLE_CLOUD_PROJECT \
                     --instanceId=spanner-migration \
                     --databaseId=migrationdb \
                     --table=Migration \
                     --importBucket=$BUCKET \
                     --runner=dataflow"
    
    1. 가져오기 작업의 진행률을 보려면 Cloud Console에서 Dataflow로 이동합니다.

      Dataflow로 이동

    2. 작업을 실행하는 동안 실행 그래프를 살펴보고 로그를 검토할 수 있습니다. 상태실행 중으로 표시되는 작업을 클릭합니다.

      실행 중인 가져오기 작업

  2. 각 단계를 클릭하여 얼마나 많은 요소가 처리되었는지 확인합니다. 가져오기가 완료되면 모든 단계가 성공이라고 표시됩니다. 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"
    

    다음과 같은 출력이 표시됩니다.

    $ gcloud spanner databases execute-sql migrationdb --instance=spanner-migration --sql="select * from Migration limit 1"
    Username    PointsEarned  ReminderDate  Subscribed  Zipcode
    aallen2538  1606          2018-06-18    False       17303
    
  5. 이전 단계에서 Spanner 쿼리에서 반환된 것과 동일한 Username로 Amazon DynamoDB 테이블을 쿼리합니다. 예: aallen2538 값은 데이터베이스에 따라 달라집니다.

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

    다른 필드의 값이 Spanner 출력의 값과 일치해야 합니다. 다음과 같은 출력이 표시됩니다.

    $ aws dynamodb get-item --table-name Migration --key '{"Username": {"S": "aallen2538"}}'
    {
        "Item": {
            "Username": {
                "S": "aallen2538"
            },
            "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
    

    다음과 같은 출력이 표시됩니다.

    $ gcloud pubsub subscriptions create spanner-migration --topic spanner-migration
    Created subscription [projects/your-project/subscriptions/spanner-migration].
    
  2. Pub/Sub로 들어오는 변경사항을 스트림하여 Spanner 테이블에 변경사항을 쓰려면 Cloud Shell에서 Dataflow 작업을 실행합니다.

    cd ~/dynamodb-spanner-migration/dataflow
    mvn exec:java \
        -Dexec.mainClass=com.example.spanner_migration.SpannerStreamingWrite \
        -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"
    
    1. 일괄 로드 단계와 마찬가지로 작업 진행률을 보려면 Cloud Console에서 Dataflow로 이동합니다.

      Dataflow로 이동

    2. 상태실행 중인 작업을 클릭합니다.

      실행 중인 작업

      처리 그래프는 이전과 비슷한 출력을 표시하지만, 처리된 항목은 각각 상태 창에서 계산됩니다. 시스템 지연 시간은 변경사항이 Spanner 테이블에 반영되기 전에 예상되는 지연 시간을 대략적으로 추정한 시간입니다.

      지연 시간으로 인해 실행 중인 프로세스

일괄 로드 단계에서 실행한 Dataflow 작업은 유한한 입력값 집합이었으며, 이를 제한된 데이터 세트라고도 합니다. 이 Dataflow 작업은 Pub/Sub를 스트리밍 소스로 사용하며, 무제한으로 간주됩니다. 이 2가지 유형의 소스에 대한 자세한 내용은 Apache Beam 프로그래밍 가이드의 PCollections 섹션을 참조하세요. 이 단계의 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'"
    

    삽입된 행이 출력에 표시됩니다.

    $ 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 None None False
  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
    

    다음과 같이 출력이 표시됩니다.

    $ 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'"
    

    다음과 같이 출력이 표시됩니다.

    $ 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 데이터베이스에서 일반적으로 적용되는 eventual consistency를 가지지 않습니다. 이 기능을 사용하면 앱 설계가 간소화됩니다.

색인을 사용하지 않는 쿼리를 실행합니다. 특정 열 값을 기준으로 상위 N개의 일치하는 항목을 찾습니다. 데이터베이스 효율성을 보장하기 위해 Amazon DynamoDB에서 자주 사용하는 쿼리입니다.

  1. Spanner로 이동합니다.

    Spanner로 이동

  2. 쿼리를 클릭합니다.

    쿼리 버튼

  3. 쿼리 필드에 다음 쿼리를 입력하고 쿼리 실행을 클릭합니다.

    SELECT Username,PointsEarned FROM Migration
      WHERE Subscribed=true AND
      ReminderDate > DATE_SUB(DATE(current_timestamp()), INTERVAL 3 DAY)
    

    쿼리가 실행되면 설명을 클릭하고 스캔된 행반환된 행을 기록합니다. 색인이 없으면 Spanner가 전체 테이블을 스캔하여 쿼리와 일치하는 소규모 데이터 하위 집합을 반환합니다.

    스캔된 행과 반환된 행 비교

  4. 이 데이터 집합이 자주 수행되는 쿼리를 나타내는 경우에는 Subscribed 및 ReminderDate 열에서 복합 색인을 만듭니다. Spanner 콘솔에서 색인 만들기를 클릭합니다.

  5. 텍스트로 편집을 클릭하여 켭니다.

  6. DDL 구문에 색인 정의를 입력합니다.

    CREATE INDEX SubscribedDate
    ON Migration (
      Subscribed,
      ReminderDate
    )
    
  7. 백그라운드에서 데이터베이스를 만들기 시작하려면 만들기를 클릭합니다.

    스키마 업데이트 진행 중

  8. 색인을 만든 후에는 쿼리를 다시 실행하고 색인을 추가합니다.

    SELECT Username,PointsEarned FROM
    Migration@{FORCE_INDEX=SubscribedDate}
      WHERE Subscribed=true AND
      ReminderDate > DATE_SUB(DATE(current_timestamp()), INTERVAL 3 DAY)
    

    쿼리 설명을 다시 검토합니다. 스캔된 행 수가 줄어든 것을 볼 수 있습니다. 각 단계의 반환된 행은 쿼리가 반환한 횟수와 일치합니다.

    쿼리 설명

인터리브 처리된 색인

Spanner에서 인터리브 처리된 색인을 설정할 수 있습니다. 이전 섹션에서 설명한 보조 색인은 데이터베이스 계층 구조의 루트에 있으며, 기존의 데이터베이스와 동일한 방법으로 색인을 사용합니다. 인터리브 처리된 색인은 인터리브 처리된 행의 컨텍스트 내에 있습니다. 인터리브 처리된 색인을 적용할 위치에 대한 자세한 내용은 색인 옵션을 참조하세요.

데이터 모델 조정

이 가이드의 이전하기 부분을 사용자의 상황에 맞춰 조정하려면 Apache Beam 소스 파일을 수정하세요. 실제 이전 기간에는 소스 스키마를 변경하지 않는 것이 중요합니다. 그렇지 않으면 데이터가 손실될 수 있습니다.

  1. 수신한 JSON을 파싱하고 변형을 빌드하려면 GSON을 사용합니다. JSON 정의를 데이터에 맞게 조정합니다.

    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(item.Username.s);
    
    Optional.ofNullable(item.Zipcode).ifPresent(x->{
        mutation.set("Zipcode").to(Integer.parseInt(x.n));
    });
    
    Optional.ofNullable(item.Subscribed).ifPresent(x->{
        mutation.set("Subscribed").to(Boolean.parseBoolean(x.bOOL));
    });
    
    Optional.ofNullable(item.ReminderDate).ifPresent(x->{
        mutation.set("ReminderDate").to(Date.parseDate(x.s));
    });
    
    Optional.ofNullable(item.PointsEarned).ifPresent(x->{
        mutation.set("PointsEarned").to(Integer.parseInt(x.n));
    });

이전 단계에서는 Apache Beam 소스 코드를 수정해 일괄 가져오기 작업을 수행했습니다. 파이프라인의 스트리밍 부분에 대한 소스 코드를 비슷한 방식으로 수정하세요. 마지막으로 Spanner 대상 데이터베이스의 테이블 생성 스크립트, 스키마, 색인을 조정합니다.

삭제

이 가이드에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

프로젝트 삭제

  1. Cloud Console에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

AWS 리소스 삭제

이 가이드 외의 다른 곳에서 AWS 계정을 사용하는 경우, 다음 리소스를 삭제할 때 주의하세요.

  1. Migration이라는 DynamoDB 테이블을 삭제합니다.
  2. 마이그레이션 단계 중에 만든 Amazon S3 버킷Lambda 함수를 삭제합니다.
  3. 마지막으로 이 가이드에서 만든 AWS IAM 사용자를 삭제합니다.

다음 단계