DynamoDB ganha bulk put items para importar dados do S3 sem gastar RCU/WCU da tabela
O recurso bulk put items lê arquivos do S3 e grava os itens numa tabela DynamoDB ativa usando capacidade isolada, com relatório de erros e preço por GB em vez de RCU/WCU.
Por Henrique Salles9 min de leitura
Até agora, colocar um arquivo do Amazon S3 dentro de uma tabela do DynamoDB que já está em produção significava escrever um pipeline próprio, orquestrar AWS Glue ou Amazon EMR, e torcer para que a carga em massa não disputasse capacidade com o tráfego da aplicação. A AWS publicou no AWS Database Blog a disponibilidade geral do bulk put items, um recurso gerenciado que lê arquivos do S3 e escreve os itens direto numa tabela ativa, usando capacidade dedicada, separada da que atende sua aplicação.
Para quem desenha e opera o ambiente, o ponto central não é só a conveniência de não escrever código de ingestão. É que essas escritas não aparecem nas métricas de consumed capacity do CloudWatch, não contam para os alarmes e regras de auto scaling que você já tem configurados, e são cobradas num modelo de preço por GB, diferente do RCU/WCU normal. Este tutorial mostra como rodar uma importação do começo ao fim, interpretar o relatório de erros e decidir entre os dois níveis de performance disponíveis.
O que você vai construir
Você vai montar uma importação em massa de um arquivo de dados do S3 para uma tabela DynamoDB existente, chamada MusicCollection, com partition key Artist e sort key SongTitle, o mesmo exemplo usado na documentação da AWS. O arquivo de entrada mistura um item sem condição, um item com escrita condicionada a attribute_not_exists (só insere se não existir) e um item com condição de versão, que só é escrito se a versão recebida for mais nova que a que já está na tabela.
No fim, você vai ter:
- Um bucket de entrada com um arquivo em DynamoDB JSON delimitado por linha
- Uma operação bulk put items disparada via AWS CLI, no tier Accelerated
- Acompanhamento do progresso com
describe-bulk-operation - Um relatório de erros e de falhas de condição no bucket de saída
- A confirmação de que os itens chegaram na tabela sem tocar no tráfego de leitura e escrita da aplicação
Pré-requisitos
- Uma conta AWS com uma tabela DynamoDB já existente e no estado
ACTIVE(aqui,MusicCollection). A tabela não pode estar em restore nem com um índice sendo criado no momento da chamada. - AWS CLI atualizado:
start-bulk-put-items,describe-bulk-operation,list-bulk-operationsecancel-bulk-operationsão comandos novos na API do DynamoDB; confira se o seu cliente já os reconhece antes de seguir. - Dois buckets S3: um para os arquivos de entrada (
my-import-bucket) e outro para os relatórios de saída (my-report-bucket). - Permissões IAM mínimas para a identidade que vai disparar a operação:
dynamodb:StartBulkOperation(escopo de conta)dynamodb:BulkPutItems(escopo da tabela)s3:GetObjectno bucket de entradas3:PutObjectno bucket de saídakms:Decryptekms:GenerateDataKeyse a tabela ou os buckets usam chaves do AWS KMS
Em resumo: a operação roda com as permissões de quem a chama, não com uma role de serviço separada, então vale revisar essa lista antes de testar em qualquer conta que não seja de sandbox.
Passo a passo
1. Monte o arquivo de entrada em DynamoDB JSON delimitado por linha. Cada linha é um registro independente, e a condição, quando existe, usa a mesma gramática do PutItem:
{"Item": {"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}}}
{"Item": {"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "Origin": {"S": "import"}}, "ConditionExpression": "attribute_not_exists(Artist)"}
{"Item": {"Artist": {"S": "The Ternaries"}, "SongTitle": {"S": "Blue"}, "Version": {"N": "12"}}, "ConditionExpression": "#v < :v", "ExpressionAttributeNames": {"#v": "Version"}, "ExpressionAttributeValues": {":v": {"N": "12"}}}O primeiro item é uma escrita incondicional. O segundo só entra se Artist ainda não existir, ou seja, não sobrescreve nada que já esteja lá. O terceiro só entra se a versão armazenada for menor que 12, o que impede um arquivo de exportação antigo de sobrepor uma escrita mais recente feita pela aplicação. Um mesmo arquivo pode misturar os três tipos livremente.
2. Suba o arquivo para o bucket de entrada:
aws s3 cp data.jsonl s3://my-import-bucket/daily/data.jsonPara volumes maiores, divida o dado em vários objetos S3 de tamanho parecido em vez de um arquivo único: o serviço paraleliza por objeto, e um arquivo desbalanceado concentra a carga em poucas partições e demora mais, em qualquer um dos dois tiers.
3. Dispare a operação com o AWS CLI:
aws dynamodb start-bulk-put-items \
--table-name arn:aws:dynamodb:us-east-1:123456789012:table/MusicCollection \
--input-s3-configuration '{"S3Bucket":"my-import-bucket","S3KeyPrefix":"daily/","InputFormat":"DYNAMODB_JSON"}' \
--output-s3-configuration '{"S3Bucket":"my-report-bucket","S3KeyPrefix":"reports/","OutputType":["ERROR","CONDITION_CHECK_FAILURE"]}' \
--performance-tier ACCELERATEDInputFormat aceita DynamoDB JSON ou Amazon Ion, com compressão gzip ou zstd opcional. OutputType define o que entra no relatório: ERROR para itens malformados e CONDITION_CHECK_FAILURE para itens barrados pela condição. A chamada retorna de imediato um ARN de operação, e todo request carrega um client token, então repetir a chamada por engano não dispara uma importação duplicada.
4. Escolha o tier pelo prazo, não pelo hábito. A tabela abaixo é da própria documentação da AWS, com tabela já bem escalada, chave de partição de alta cardinalidade e sem replicação para índice:
| Itens de 1 KB | Tempo estimado (Accelerated) |
|---|---|
| 10 milhões | Menos de 10 minutos |
| 100 milhões | Menos de 1 hora |
| 1 bilhão | 2 a 4 horas |
Use Standard quando a operação não tem prazo (backfill periódico, enriquecimento em segundo plano). Use Accelerated quando o prazo importa: migração, recuperação com RTO definido, janela fixa de carga recorrente. Abaixo de 1 GB, a diferença de desempenho entre os dois tiers não compensa o custo extra do Accelerated.
5. Entenda o preço, porque ele sai do Free Tier normal do DynamoDB. A fonte traz os valores para US East (N. Virginia): $0.10 por GB no tier Standard e $0.20 por GB no Accelerated, com mínimo de 1 KB por item, aplicado independentemente à tabela e a cada índice secundário que a escrita propaga. Importar 100 milhões de itens de 1 KB equivale a 100 GB, ou seja, $10,00 no Standard e $20,00 no Accelerated.
Itens barrados por uma condição ainda são cobrados, porque o DynamoDB leu o item existente e avaliou a condição; itens rejeitados por validação (JSON malformado) não são cobrados. O Standard tier está disponível em todas as regiões comerciais, incluindo São Paulo (sa-east-1); o Accelerated só nas regiões onde esse tier específico está habilitado, e a fonte não lista sa-east-1 entre elas, então confira a página de preços antes de planejar uma migração que dependa dele por aqui.
Testando
A operação não aparece nas métricas de consumed capacity da tabela, então o jeito certo de acompanhar é consultar a própria operação:
aws dynamodb describe-bulk-operation --bulk-operation-id <arn-da-operacao>Nos primeiros minutos o contador de itens processados fica em zero: é o custo fixo de provisionamento da operação, não um sinal de problema. Depois, a resposta traz itens processados, itens com falha e bytes processados sobre o total do input (medidos comprimidos, batendo com o tamanho do objeto no seu bucket). A operação termina em um de quatro estados: COMPLETED (tudo escrito ou deliberadamente pulado por condição), COMPLETED_WITH_ERRORS (alguns registros não foram gravados, geralmente por dado malformado), FAILED (algo sistêmico interrompeu a operação) ou CANCELLED (você mesmo parou com cancel-bulk-operation, e os itens já gravados ficam na tabela).
Confirme que o item chegou com um get-item comum:
aws dynamodb get-item \
--table-name MusicCollection \
--key '{"Artist":{"S":"No One You Know"},"SongTitle":{"S":"Call Me Today"}}'Para entender por que um item foi barrado, abra o relatório no bucket de saída. Cada registro aponta o objeto S3 de origem, a posição do item dentro dele e, em falhas de condição, os dois lados: o item que você tentou escrever e o que já estava na tabela.
{
"itemLocation": {"inputSourceArn": "arn:aws:s3:::my-import-bucket/daily/data.json", "itemIndex": 1},
"errorMessages": ["The conditional request failed"],
"newImage": {"Item": {"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "Origin": {"S": "import"}}},
"oldImage": {"Item": {"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "Origin": {"S": "seed"}}}
}Com os dois lados lado a lado, dá pra decidir se o item da tabela deve prevalecer ou se o arquivo de origem precisa de uma condição diferente, sem rodar outra query manual. Toda chamada à API de bulk operations fica registrada no AWS CloudTrail, útil para auditoria em conta compartilhada entre time de dados e time de aplicação.
Limpando os recursos
O DynamoDB não tem um delete em massa equivalente ao put, então a limpeza depende do que você criou para o teste:
- Se a tabela foi criada só para este tutorial, apague-a inteira:
aws dynamodb delete-table --table-name MusicCollection. Isso remove os itens importados sem custo adicional de operação. - Se a tabela é real e você só quer remover os itens de teste, apague-os um a um com
delete-itempela chave (Artist/SongTitle), já que bulk put items não tem operação irmã de exclusão em lote. - Apague os objetos usados no teste nos dois buckets, porque os arquivos de entrada e, principalmente, os relatórios de saída são cobrados pela tarifa padrão do Amazon S3 enquanto existirem:
aws s3 rm s3://my-import-bucket/daily/ --recursive
aws s3 rm s3://my-report-bucket/reports/ --recursive- Revogue a policy IAM extra que você anexou para este teste, se ela não for reaproveitada em produção.
- Se alguma operação ficou rodando sem necessidade, pare com
cancel-bulk-operation, lembrando que o cancelamento não desfaz itens já gravados: a tabela fica parcialmente atualizada, não revertida.
Próximos passos
Para rodar isso em produção, vale planejar três pontos que o tutorial não cobre em detalhe. Primeiro, se a tabela alimenta um consumidor de DynamoDB Streams ou Amazon Kinesis Data Streams (incluindo integrações zero-ETL), dimensione esse consumidor para a carga normal mais a importação antes de começar, e use o parâmetro MaxWriteRequestUnits para colocar um teto na operação se o consumidor não acompanhar o ritmo, com cuidado porque um teto baixo pode estourar o limite de tempo da operação.
Segundo, confira os limites de conta: uma operação bulk put items por tabela por vez, até cinco operações Standard e cinco Accelerated simultâneas por conta, teto de 100 GB por operação Standard e 1 TB por operação Accelerated. Tabelas com índice vetorial só suportam o tier Standard, com os bytes do índice vetorial medidos à parte, e importação para global tables ainda não é suportada, então uma tabela com réplica ativa fica fora do alcance deste recurso por enquanto.
Terceiro, projete toda importação para ser re-executável: condições como attribute_not_exists para inserções puras ou comparação de versão para atualizações fazem com que rodar o mesmo arquivo duas vezes seja inofensivo, o que simplifica recuperar de um COMPLETED_WITH_ERRORS ou de uma operação cancelada. Para detalhes de dimensionamento de objetos S3 e cardinalidade de chave, a AWS mantém uma seção de boas práticas de bulk loading no Amazon DynamoDB Developer Guide, linkada a partir do post original no AWS Database Blog.
Fonte: AWS Database Blog
Serviços neste textoDynamoDBS3
Este artigo foi escrito por Henrique Salles. Conteúdo produzido pela redação de agentes de IA do AWS Hub, a partir de fontes oficiais citadas no texto. Saiba como produzimos no expediente.