Como migrar do DynamoDB para o Cloud Spanner

Neste tutorial, descrevemos como migrar do Amazon DynamoDB para o Spanner. Ele é destinado principalmente aos proprietários de apps que querem migrar de um sistema NoSQL para o Spanner, um sistema de banco de dados SQL totalmente relacional, tolerante a falhas e altamente escalonável que oferece suporte a transações. Se você tiver uso consistente de tabelas do Amazon DynamoDB, em termos de tipos e layout, o mapeamento para o Spanner será simples. Se as tabelas do Amazon DynamoDB contiverem tipos e valores de dados arbitrários, talvez seja mais fácil migrar para outros serviços NoSQL, como o Datastore ou o Firebase.

Neste tutorial, pressupomos que você tenha familiaridade com esquemas de banco de dados, tipos de dados, os fundamentos do NoSQL e sistemas de bancos de dados relacionais. O tutorial depende da execução de tarefas predefinidas para realizar uma migração de amostra. Após o tutorial, é possível modificar o código e as etapas fornecidas para corresponder ao seu ambiente.

O seguinte diagrama arquitetural descreve os componentes usados no tutorial para migrar dados:

Diagrama arquitetural dos componentes de migração

Objetivos

  • Migrar dados do Amazon DynamoDB para o Spanner.
  • Criar um banco de dados do Spanner e uma tabela de migração.
  • Mapear um esquema NoSQL em um esquema relacional.
  • Criar e exportar um conjunto de dados de amostra que use o Amazon DynamoDB.
  • Transferir dados entre o Amazon S3 e o Cloud Storage.
  • Usar o Dataflow para carregar dados no Spanner.

Custos

Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:

  • GKE
  • Pub/Sub
  • Cloud Storage
  • Dataflow

As cobranças do Spanner são baseadas no número de horas do nó e na quantidade de dados armazenados durante o ciclo de faturamento mensal. Durante o tutorial, você usa uma configuração mínima desses recursos, que são limpos no final. Para cenários reais, faça uma estimativa dos requisitos de capacidade e armazenamento e use a documentação das instâncias do Spanner para determinar o número de nós necessários.

Além dos recursos do Google Cloud, este tutorial usa os seguintes recursos do Amazon Web Services (AWS):

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

Esses serviços são necessários apenas durante o processo de migração. No final do tutorial, siga as instruções para limpar todos os recursos e evitar cobranças desnecessárias. Use a calculadora de preços da AWS (em inglês) para estimar esses custos.

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem ser qualificados para uma avaliação gratuita.

Antes de começar

  1. Faça login na sua conta do Google.

    Se você ainda não tiver uma, inscreva-se.

  2. No Console do Cloud, na página do seletor de projetos, selecione ou crie um projeto do Cloud.

    Acessar a página do seletor de projetos

  3. Verifique se a cobrança está ativada para o seu projeto do Google Cloud. Saiba como confirmar se a cobrança está ativada para o seu projeto.

  4. Ative as APIs Spanner, Pub/Sub, Compute Engine, and Dataflow.

    Ative as APIs

Ao concluir este tutorial, exclua os recursos criados para evitar o faturamento contínuo. Para mais informações, consulte Como fazer a limpeza.

Como preparar o ambiente

Neste tutorial, você executa comandos no Cloud Shell. O Cloud Shell fornece acesso à linha de comando no Google Cloud e inclui o SDK do Cloud e outras ferramentas necessárias para o desenvolvimento do Google Cloud. O Cloud Shell pode demorar vários minutos para inicializar.

  1. Ative o Cloud Shell.

    ATIVAR o Cloud Shell

  2. Defina a zona padrão do Compute Engine. Por exemplo, us-central1-b

    gcloud config set compute/zone us-central1-b
    
  3. Clone o repositório do GitHub que contém o código de amostra.

    git clone https://github.com/GoogleCloudPlatform/dynamodb-spanner-migration.git
    
  4. Acesse o diretório clonado.

    cd dynamodb-spanner-migration
    
  5. Crie um ambiente virtual em Python.

    virtualenv --python python2 env
    
  6. Ative o ambiente virtual.

    source env/bin/activate
    
  7. Instale os módulos necessários do Python.

    pip install -r requirements.txt
    

Como configurar o acesso da AWS

Neste tutorial, você cria e exclui tabelas do Amazon DynamoDB, buckets do Amazon S3 e outros recursos. Para acessar esses recursos, primeiro você precisa criar as permissões exigidas pelo AWS Identity and Access Management (IAM). Use uma conta de teste ou sandbox da AWS para evitar afetar os recursos de produção na mesma conta.

Criar uma função do AWS IAM para o AWS Lambda

Nesta seção, você cria uma função do AWS IAM que o AWS Lambda usa em uma etapa posterior do tutorial.

  1. No console da AWS, acesse a seção IAM, clique em Papéis e selecione Criar papel.
  2. Em Escolher o serviço que usará esse papel, clique em Lambda e, em seguida, selecione Próximo: permissões.
  3. Na caixa Tipo de política, digite AWSLambdaDynamoDBExecutionRole.
  4. Marque a caixa de seleção AWSLambdaDynamoDBExecutionRole e clique em Próximo: revisão.
  5. Na caixa Nome do papel, digite dynamodb-spanner-lambda-role e clique em Criar papel.

Criar um usuário do AWS IAM

Siga estas etapas para criar um usuário do AWS IAM com acesso programático aos recursos da AWS, que são usados em todo o tutorial.

  1. Ainda na seção IAM do console da AWS, clique em Usuários e selecione Adicionar usuário.
  2. Na caixa Nome de usuário, digite dynamodb-spanner-migration.
  3. Em Tipo de acesso, clique em Acesso programático.

  4. Clique em Next: Permissions.

  5. Clique em Attach existing policies directly e selecione as duas políticas a seguir:

    • AmazonDynamoDBFullAccesswithDataPipeline
    • AmazonS3FullAccess
  6. Clique em Próximo: revisão e, em seguida, clique em Criar usuário.

  7. Clique em Mostrar para ver as credenciais. O ID da chave de acesso e a chave de acesso secreta são exibidos para o usuário recém-criado. Deixe essa janela aberta por enquanto porque as credenciais são necessárias na seção a seguir. Armazene com segurança essas credenciais porque com elas é possível fazer alterações em sua conta e afetar seu ambiente. No final deste tutorial, exclua o usuário do IAM.

Configurar a interface da linha de comando da AWS

  1. No Cloud Shell, configure a interface da linha de comando (CLI, na sigla em inglês) da AWS.

    aws configure
    

    A seguinte resposta é exibida:

    $ 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$
    
    • Digite ACCESS KEY ID e SECRET ACCESS KEY da conta do IAM da AWS que você criou.
    • No campo Nome da região padrão, insira us-west-2. Deixe outros campos com os valores padrão.
  2. Feche a janela do console do AWS IAM.

Noções básicas sobre o modelo de dados

A seção a seguir descreve as semelhanças e as diferenças entre tipos de dados, chaves e índices do Amazon DynamoDB e do Spanner.

Tipos de dados

O Spanner usa tipos de dados SQL padrão. A tabela a seguir descreve como os tipos de dados (em inglês) do Amazon DynamoDB se relacionam com os tipos de dados do Cloud Spanner.

Amazon DynamoDB Spanner
Número Dependendo da precisão ou uso pretendido, pode ser mapeado como INT64, FLOAT64, TIMESTAMP ou DATE.
String String
Booleano BOOL
Nulo Nenhum tipo explícito. Colunas podem conter valores nulos.
Binário Bytes
Conjuntos Matriz
Mapa e lista Struct se a estrutura for consistente e puder ser descrita usando a sintaxe da tabela DDL.

Chave primária

Uma chave primária do Amazon DynamoDB estabelece exclusividade e pode ser uma chave de hash ou uma combinação de uma chave de hash, além de uma chave de intervalo. Neste tutorial, iniciamos modelando a migração de uma tabela do Amazon DynamoDB em que a chave primária é uma chave de hash. Essa chave de hash se torna a chave principal da sua tabela do Spanner. Posteriormente, na seção sobre tabelas intercaladas, você modela uma situação em que uma tabela do Amazon DynamoDB usa uma chave primária composta de uma chave de hash e uma chave de intervalo.

Índices secundários

Tanto o Amazon DynamoDB quanto o Spanner são compatíveis com a criação de um índice em um atributo de chave não primária. Anote todos os índices secundários na tabela do Amazon DynamoDB para criá-los na tabela do Spanner, que é abordada em uma seção posterior deste tutorial.

Tabela de amostra

Para facilitar este tutorial, migre a seguinte tabela de amostra do Amazon DynamoDB para o Spanner:

Amazon DynamoDB Spanner
Nome da tabela Migration Migration
Chave primária "Username" : String "Username" : STRING(1024)
Tipo de chave Hash n/a
Outros campos Zipcode: Number Subscribed: Boolean ReminderDate: String PointsEarned: Number Zipcode: INT64 Subscribed: BOOL ReminderDate: DATE PointsEarned: INT64

Como preparar a tabela do Amazon DynamoDB

Na seção a seguir, você cria uma tabela de origem do Amazon DynamoDB e a preenche com dados.

  1. No Cloud Shell, crie uma tabela do Amazon DynamoDB que use os atributos da tabela de amostra.

    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. Verifique se o status da tabela é ACTIVE.

    aws dynamodb describe-table --table-name Migration \
        --query 'Table.TableStatus'
    
  3. Preencha a tabela com dados de amostra.

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

Como criar um banco de dados do Spanner

Você cria uma instância de nó único, que é apropriada para testes e o escopo deste tutorial. Para uma implantação de produção, consulte a documentação de instâncias do Spanner para determinar a contagem de nós apropriada para atender aos requisitos de desempenho de seu banco de dados.

Neste exemplo, você cria um esquema de tabela ao mesmo tempo que o banco de dados. Também é possível (e comum) realizar atualizações de esquema depois de criar o banco de dados.

  1. Crie uma instância do Spanner na mesma região em que você define a zona padrão do Compute Engine. Por exemplo, us-central1

    gcloud spanner instances create spanner-migration \
        --config=regional-us-central1 --nodes=1 \
        --description="Migration Demo"
    
  2. Crie um banco de dados na instância do Spanner com a tabela de exemplo.

    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)"
    

Como pausar o banco de dados

Nas próximas seções, mostramos como exportar a tabela de origem do Amazon DynamoDB e configurar a replicação do Pub/Sub para capturar as alterações no banco de dados que ocorrerem durante a exportação. Se as alterações em seu banco de dados não forem idempotentes e não for seguro gravar os mesmos dados mais de uma vez, é melhor executar as etapas a seguir durante um período de manutenção, quando é possível pausar as alterações do app na tabela.

Alterações de stream no Pub/Sub

Use uma função do AWS Lambda para transmitir alterações de banco de dados no Pub/Sub.

  1. No Cloud Shell, ative os fluxos do Amazon DynamoDB na sua tabela de origem.

    aws dynamodb update-table --table-name Migration \
        --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
    
  2. Configure um tópico do Pub/Sub para receber as alterações.

    gcloud pubsub topics create spanner-migration
    

    A seguinte saída é exibida:

    $ gcloud pubsub topics create spanner-migration
    Created topic [projects/your-project/topics/spanner-migration].
    
  3. Crie uma conta de serviço do IAM para enviar atualizações da tabela ao tópico do Pub/Sub.

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

    A seguinte saída é exibida:

    $ gcloud iam service-accounts create spanner-migration --display-name="Spanner Migration"
    Created service account [spanner-migration].
    
  4. Crie uma vinculação de política do IAM para que a conta de serviço tenha permissão para publicar no Pub/Sub. Substitua GOOGLE_CLOUD_PROJECT pelo nome do projeto do 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
    

    A seguinte resposta é exibida:

    $ 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. Crie credenciais para a conta de serviço.

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

    A seguinte resposta é exibida:

    $ 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. Prepare e empacote a função do AWS Lambda para enviar as alterações da tabela do Amazon DynamoDB ao tópico do 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. Crie uma variável para capturar o Nome de Recurso da Amazon (ARN na sigla em inglês) da função de execução do Lambda que você criou anteriormente.

    LAMBDA_ROLE=$(aws iam list-roles \
        --query 'Roles[?RoleName==`dynamodb-spanner-lambda-role`].[Arn]' \
        --output text)
    
  8. Use o pacote pubsub-lambda.zip para criar a função do 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}"
    

    A seguinte resposta é exibida:

    $ 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. Crie uma variável para capturar o ARN do fluxo do Amazon DynamoDB para sua tabela.

    STREAMARN=$(aws dynamodb describe-table \
        --table-name Migration \
        --query "Table.LatestStreamArn" \
        --output text)
    
  10. Anexe a função Lambda à tabela do Amazon DynamoDB.

    aws lambda create-event-source-mapping --event-source $STREAMARN \
        --function-name dynamodb-spanner-lambda --enabled \
        --starting-position TRIM_HORIZON
    
  11. Para otimizar a capacidade de resposta durante o teste, adicione --batch-size 1 ao final do comando anterior, que aciona a função sempre que você cria, atualiza ou exclui um item.

    A seguinte resposta é exibida:

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

Exportar a tabela do Amazon DynamoDB para o Amazon S3

  1. No Cloud Shell, crie uma variável para um nome de um bucket que você vai usar em várias das seções a seguir.

    BUCKET=$DEVSHELL_PROJECT_ID-dynamodb-spanner-export
    
  2. Crie um bucket do Amazon S3 para receber a exportação do DynamoDB.

    aws s3 mb s3://$BUCKET
    
  3. No Console de Gerenciamento da AWS, clique em Data Pipeline.

  4. Clique em Create new pipeline para definir o job de exportação.

  5. No campo Name, insira Export to Amazon S3.

  6. Para Source, selecione o seguinte:

    • Build using a template.
    • Export DynamoDB table to Amazon S3.
  7. Na seção Parâmetros, defina o seguinte:

    1. No campo Nome da tabela do DynamoDB de origem, digite Migration.
    2. No campo Pasta S3 de saída, clique no ícone Pasta e selecione o bucket [Your-Project-ID]-dynamodb-spanner-export do Amazon S3 que você acabou de criar, em que [YOUR-PROJECT-ID] representa o código do projeto do Google Cloud.
    3. Para consumir toda a capacidade de leitura disponível durante a exportação, no campo Taxa de capacidade de leitura do DynamoDB, digite 1. Em um ambiente de produção, você ajusta esse valor para não atrapalhar as operações ativas.
    4. No campo região da tabela do DynamoDB, digite o nome da região, por exemplo, us-west-2.
  8. Para iniciar os jobs de backup imediatamente, na seção Programação para Executar, clique em Na ativação do pipeline.

  9. Na Configuração do pipeline, no campo Logging, digite Disabled. Se você estiver seguindo este guia para migrar uma tabela de produção, deixe essa opção ativada e aponte para um bucket separado do Amazon S3 para registros para ajudá-lo a solucionar erros. Deixe outros parâmetros com as configurações padrão.

  10. Para iniciar o processo de backup, clique em Activate.

  11. Se você receber uma solicitação para conferir os avisos de validação, clique em Activate. Em uma situação de produção, você define uma duração máxima para o job e ativa a geração de registros.

  12. Clique em Refresh para atualizar o status do processo de backup. O job leva vários minutos para criar os recursos e concluir a exportação. Em um ambiente de produção, é possível acelerar esse processo modificando os jobs do Pipeline de dados para usar mais recursos de EMR.

    Quando o processo terminar, observe o bucket de saída.

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

    O job de exportação é feito quando há um arquivo chamado _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
    

Como abrir o banco de dados

Se você pausou gravações no banco de dados antes de exportar, é hora de reativar as gravações no banco de dados. Agora que a entrega de Pub/Sub está em vigor, é possível avançar quaisquer alterações de tabela que ocorreram após a exportação.

Copiar a tabela exportada para o Cloud Storage

  1. No Cloud Shell, crie um bucket do Cloud Storage para receber os arquivos exportados do Amazon S3.

    gsutil mb gs://$BUCKET
    
  2. Sincronize os arquivos do Amazon S3 com o Cloud Storage. Para a maioria das operações de cópia, o comando rsync é efetivo. Se os arquivos de exportação forem grandes (vários GB ou mais), use o serviço de transferência do Cloud Storage para gerenciar a transferência em segundo plano.

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

    A seguinte resposta é exibida:

    $ 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.
    

Importar os dados em lotes

  1. Para gravar os dados dos arquivos exportados na tabela do Spanner, execute um job do Dataflow com código de amostra do 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. Para acompanhar o progresso do job de importação, no Console do Cloud, acesse o Dataflow.

      ACESSAR o Dataflow

    2. Enquanto o job está em execução, é possível assistir ao gráfico de execução para examinar os registros. Clique no job que mostra o Status Em execução.

      Como executar o job de importação

  2. Clique em cada etapa para ver quantos elementos foram processados. A importação é concluída quando todas as etapas forem bem-sucedidas. O mesmo número de elementos criados em sua tabela do Amazon DynamoDB é processado em cada etapa.

    Estágios de sucesso do job de importação

  3. Verifique se o número de registros na tabela de Spanner de destino corresponde ao número de itens na tabela do 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"

    A seguinte resposta é exibida:

    $ 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. Crie uma amostra de entradas aleatórias em cada tabela para garantir que os dados sejam consistentes.

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

    A seguinte resposta é exibida:

    $ 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. Consulte a tabela do Amazon DynamoDB com o mesmo Username retornado da consulta do Spanner na etapa anterior. Por exemplo, aallen2538; Seu valor é específico para o banco de dados.

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

    Os valores dos outros campos precisam corresponder aos valores da saída do Spanner. A seguinte resposta é exibida:

    $ 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
            }
        }
    }
    

Replicar novas alterações

Quando o job de importação em lote estiver concluído, você configura um job de streaming para gravar atualizações contínuas da tabela de origem no Spanner. Você assina os eventos do Pub/Sub e os escreve no Spanner

A função Lambda que você criou está configurada para capturar alterações na tabela de origem do Amazon DynamoDB e publicá-las no Pub/Sub.

  1. Crie uma assinatura para o tópico do Pub/Sub para o qual o AWS Lambda envia eventos.

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

    A seguinte resposta é exibida:

    $ gcloud pubsub subscriptions create spanner-migration --topic spanner-migration
    Created subscription [projects/your-project/subscriptions/spanner-migration].
    
  2. Para transmitir as alterações que chegam ao Pub/Sub para gravar na tabela do Spanner, execute o job do Dataflow no Cloud Shell.

    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. Semelhante à etapa de carregamento em lote, para acompanhar o progresso do job, no Console do Cloud, acesse o Dataflow.

      ACESSAR o Dataflow

    2. Clique no job que tem o Status Em execução.

      Job em execução

      O gráfico de processamento mostra uma resposta semelhante à anterior, mas cada item processado é contado na janela de status. O tempo de atraso do sistema é uma estimativa aproximada de quanto atraso esperar antes que as alterações apareçam na tabela do Spanner.

      Processos em execução devido ao tempo de atraso

O job do Dataflow que você executou na fase de carregamento em lote era um conjunto finito de entrada, também conhecido como um conjunto de dados limitado. Esse job do Dataflow usa o Pub/Sub como uma fonte de streaming e é considerado ilimitado. Para ver mais informações sobre esses dois tipos de fontes, consulte a seção sobre PCollections no guia de programação do Apache Beam. O job do Dataflow nesta etapa precisa permanecer ativo. Portanto, ele não é encerrado quando concluído. O job de streaming do Dataflow permanece no status Em execução, em vez do status Concluído.

Verificar a replicação

Você faz algumas alterações na tabela de origem para verificar se as alterações são replicadas para a tabela do Spanner.

  1. Consulte uma linha inexistente no Spanner.

    gcloud spanner databases execute-sql migrationdb \
        --instance=spanner-migration --sql=\
        "SELECT * FROM Migration WHERE Username='my-test-username'"
    
  2. Crie um registro no Amazon DynamoDB com a mesma chave usada na consulta do Spanner. Se o comando for executado com sucesso, não haverá resposta.

    aws dynamodb put-item \
        --table-name Migration \
        --item '{"Username" : {"S" : "my-test-username"}, "Subscribed" : {"BOOL" : false}}'
    
  3. Execute a consulta original novamente para verificar se a linha está agora no Spanner.

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

    A resposta mostra a linha inserida:

    $ 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. Altere alguns atributos no item original e atualize a tabela do 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
    

    A resposta aparece da seguinte maneira:

    $ 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. Verifique se as alterações são propagadas para a tabela do Spanner.

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

    A resposta aparece da seguinte maneira:

    $ 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. Exclua o item de teste da tabela de origem do Amazon DynamoDB.

    aws dynamodb delete-item \
        --table-name Migration \
        --key '{"Username": {"S":"my-test-username"}}'
    
  7. Verifique se a linha correspondente foi excluída da tabela do Spanner. Quando a mudança é propagada, o comando a seguir não retorna nenhuma linha:

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

Como usar tabelas intercaladas

O Spanner é compatível com o conceito de tabelas intercaladas. Esse é um modelo de concepção em que um item de nível superior tem vários itens aninhados relacionados a esse item de nível superior, como um cliente e os pedidos, ou um jogador e as pontuações no jogo. Se sua tabela de origem do Amazon DynamoDB usa uma chave primária composta de uma chave de hash e uma chave de intervalo, é possível modelar um esquema de tabela intercalada, conforme mostrado no diagrama a seguir. Essa estrutura permite consultar com eficiência a tabela intercalada ao unir campos na tabela pai.

Tabela de usuários comparada à tabela de pedidos

Aplicar índices secundários

É uma prática recomendada aplicar índices secundários às tabelas do Spanner depois de carregar os dados. Agora que a replicação está funcionando, você configura um índice secundário para acelerar as consultas. Assim como as tabelas do Spanner, os índices secundários do Spanner são totalmente consistentes. Eles não têm consistência eventual, o que é comum em muitos bancos de dados NoSQL. Esse recurso pode ajudar a simplificar a concepção do aplicativo.

Execute uma consulta que não use nenhum índice. Você está procurando as N ocorrências principais, considerando um determinado valor de coluna. Essa é uma consulta comum no Amazon DynamoDB para eficiência do banco de dados.

  1. Acesse o Spanner.

    ACESSAR o Spanner

  2. Clique em CONSULTA.

    Botão Consulta

  3. No campo Consulta, insira a consulta a seguir e clique em Executar consulta.

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

    Depois que a consulta for executada, clique em Explicação e anote as linhas verificadas em relação às linhas retornadas. Sem um índice, o Spanner verifica a tabela inteira para retornar um pequeno subconjunto de dados que corresponde à consulta.

    Linhas verificadas em comparação com as linhas retornadas

  4. Se isso representar uma consulta comum, crie um índice composto nas colunas Subscribed e ReminderDate. No console do Spanner, clique em Criar índice.

  5. Clique para ativar Editar como texto.

  6. Nas instruções DDL, insira a definição do índice.

    CREATE INDEX SubscribedDate
    ON Migration (
      Subscribed,
      ReminderDate
    )
    
  7. Para começar a construir o banco de dados em segundo plano, clique em Criar.

    Atualização do esquema em andamento

  8. Depois que o índice for criado, execute a consulta novamente e adicione o índice.

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

    Examine a explicação da consulta novamente. Observe que o número de linhas verificadas diminuiu. As linhas retornadas em cada etapa correspondem ao número retornado pela consulta.

    Explicação da consulta

Índices intercalados

É possível configurar índices intercalados no Spanner. Os índices secundários discutidos na seção anterior estão na raiz da hierarquia do banco de dados e usam índices da mesma maneira que um banco de dados convencional. Um índice intercalado está dentro do contexto de sua linha intercalada. Consulte opções de índice para ver mais detalhes sobre onde aplicar índices intercalados.

Como ajustar ao modelo de dados

Para adaptar a parte de migração deste tutorial à sua própria situação, modifique os arquivos de origem do Apache Beam. É importante que você não altere o esquema de origem durante a janela de migração real, caso contrário, poderá perder dados.

  1. Para analisar o JSON recebido e criar mutações, use o GSON. Ajuste a definição JSON para corresponder aos seus dados.

    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. Ajuste o mapeamento JSON correspondente.

    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));
    });

Nas etapas anteriores, você modificou o código-fonte do Apache Beam para importação em massa. Modifique o código-fonte da parte de streaming do pipeline de maneira semelhante. Por fim, ajuste os scripts de criação de tabelas, esquemas e índices do banco de dados de destino do Spanner.

Como fazer a limpeza

Para evitar que os recursos usados neste tutorial sejam cobrados na conta do Google Cloud Platform, faça o seguinte:

Excluir o projeto

  1. No Console do Cloud, acesse a página Gerenciar recursos:

    Acessar a página "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir recursos da AWS

Se sua conta da AWS for usada fora deste tutorial, tenha cuidado ao excluir os seguintes recursos:

  1. Exclua a tabela do DynamoDB chamada Migração.
  2. Exclua o bucket do Amazon S3 e a função Lambda que você criou durante as etapas de migração.
  3. Por fim, exclua o usuário do AWS IAM criado durante este tutorial.

A seguir