Aprenda o que é o Amazon DynamoDB, como seu modelo NoSQL funciona e padrões práticos de design para sistemas escaláveis e de baixa latência.

Amazon DynamoDB é um serviço de banco de dados NoSQL totalmente gerenciado da AWS, projetado para aplicações que precisam de leituras e gravações com latência consistentemente baixa em praticamente qualquer escala. “Totalmente gerenciado” significa que a AWS cuida do trabalho de infraestrutura — provisionamento de hardware, replicação, patching e muitas tarefas operacionais — para que as equipes possam focar em entregar funcionalidades em vez de administrar servidores de banco de dados.
No núcleo, o DynamoDB armazena dados como itens (linhas) dentro de tabelas, mas cada item pode ter atributos flexíveis. O modelo de dados é melhor entendido como uma mistura de:
Equipes escolhem DynamoDB quando querem performance previsível e operações mais simples para cargas que não se ajustam bem a joins relacionais. É comumente usado em microsserviços (cada serviço tendo seus próprios dados), apps serverless com tráfego em rajadas e sistemas orientados a eventos que reagem a mudanças nos dados.
Este post percorre os blocos de construção (tabelas, chaves e índices), como modelar em torno de padrões de acesso (incluindo design de tabela única), como funcionam escalabilidade e modos de capacidade, e padrões práticos para transmitir mudanças a uma arquitetura orientada a eventos.
DynamoDB é organizado em torno de alguns blocos simples, mas os detalhes importam porque determinam como você modela dados e quão rápidas (e custo-efetivas) serão as requisições.
Uma tabela é o container de nível superior. Cada registro na tabela é um item (semelhante a uma linha), e cada item é um conjunto de atributos (semelhante a colunas).
Ao contrário de bancos relacionais, itens na mesma tabela não precisam compartilhar os mesmos atributos. Um item pode ter {status, total, customerId}, enquanto outro inclui {status, shipmentTracking} — o DynamoDB não exige um esquema fixo.
Todo item é identificado de forma única por uma chave primária, e o DynamoDB suporta dois tipos:
Na prática, chaves compostas permitem padrões de acesso “agrupados”, como “todos os pedidos de um cliente, do mais novo para o mais antigo”.
Um Query lê itens por chave primária (ou pela chave de um índice). Ele mira uma chave de partição específica e pode filtrar por intervalos na chave de ordenação — este é o caminho eficiente e preferido.
Um Scan percorre toda a tabela (ou índice) e depois aplica filtros. É fácil começar com ele, mas costuma ser mais lento e mais caro em escala.
Algumas restrições que você encontrará cedo:
Esses fundamentos fundamentam tudo o que vem a seguir: padrões de acesso, escolhas de índices e características de performance.
DynamoDB costuma ser descrito tanto como um armazenamento key-value quanto como um banco de documentos. Isso é preciso, mas ajuda entender o que cada lado implica no design do dia a dia.
No cerne, você recupera dados por chave. Forneça os valores da chave primária e o DynamoDB retorna um único item. Essa busca por chave é o que entrega armazenamento de baixa latência e previsível para muitas cargas.
Ao mesmo tempo, um item pode conter atributos aninhados (maps e lists), o que o faz se comportar como um banco de documentos: você pode armazenar payloads estruturados sem definir um esquema rígido previamente.
Itens mapeiam naturalmente para dados tipo JSON:
profile.name, profile.address).Isso é ideal quando uma entidade é normalmente lida inteira — como um perfil de usuário, um carrinho de compras ou um bundle de configuração.
DynamoDB não oferece joins no servidor. Se seu app precisa buscar “um pedido mais seus itens de linha mais o status de envio” em um único caminho de leitura, você frequentemente desnormaliza: copia alguns atributos em múltiplos itens ou incorpora subestruturas pequenas diretamente dentro do item.
Desnormalizar aumenta a complexidade de escrita e pode criar fan-out nas atualizações. O ganho é reduzir round trips e acelerar leituras — muitas vezes a diferença crítica em sistemas escaláveis.
As consultas mais rápidas no DynamoDB são as que você pode expressar como “me dê esta partição” (e opcionalmente “dentro desta partição, me dê este intervalo”). Por isso a escolha da chave é sobre como você lê, não apenas como armazena.
A chave de partição determina qual partição física armazena um item. O DynamoDB faz hash desse valor para espalhar dados e tráfego. Se muitas requisições se concentrarem em um pequeno conjunto de valores de chave de partição, você pode criar partições “quentes” e atingir limites de throughput mesmo que a tabela esteja majoritariamente ociosa.
Boas chaves de partição:
"GLOBAL")Com uma chave de ordenação, itens que compartilham a mesma chave de partição são armazenados juntos e ordenados pela chave de ordenação. Isso habilita eficientemente:
BETWEEN, begins_with)Um padrão comum é compor a chave de ordenação, como TYPE#id ou TS#2025-12-22T10:00:00Z, para suportar diversos formatos de consulta sem tabelas extras.
PK = USER#<id> (simples GetItem)PK = USER#<id>, SK begins_with ORDER# (ou SK = CREATED_AT#...)PK = DEVICE#<id>, SK = TS#<timestamp> com BETWEEN para janelas de tempoSe sua chave de partição alinha com suas consultas de maior volume e distribui uniformemente, você terá leituras e gravações com latência consistentemente baixa. Se não alinhar, você compensará com scans, filtros ou índices extras — cada um aumentando custo e risco de hot keys.
Índices secundários dão ao DynamoDB caminhos alternativos de consulta além da chave primária da tabela. Em vez de remodelar a tabela base sempre que surge um novo padrão de acesso, você pode adicionar um índice que re-chaveia os mesmos itens para uma consulta diferente.
Um Global Secondary Index (GSI) tem sua própria chave de partição (e chave de ordenação opcional) que pode ser completamente diferente da tabela. É “global” porque cobre todas as partições da tabela e pode ser adicionado ou removido a qualquer momento. Use um GSI quando precisar de um novo padrão de acesso que não cabe na chave original — por exemplo, consultar pedidos por customerId quando a tabela é keyeada por orderId.
Um Local Secondary Index (LSI) compartilha a mesma chave de partição da tabela base, mas usa uma chave de ordenação diferente. LSIs devem ser definidos na criação da tabela. Eles são úteis quando você quer múltiplas ordenações dentro do mesmo grupo de entidade (mesma chave de partição), como buscar pedidos de um cliente ordenados por createdAt ou por status.
A projeção determina quais atributos o DynamoDB armazena no índice:
Cada escrita na tabela base pode acionar escritas em um ou mais índices. Mais GSIs e projeções amplas aumentam o custo de escrita e o consumo de capacidade. Planeje índices em torno de padrões estáveis e mantenha atributos projetados no mínimo necessário quando possível.
A escalabilidade do DynamoDB começa com uma escolha: On-Demand ou Provisioned. Ambos podem alcançar throughput muito alto, mas se comportam de maneiras distintas sob tráfego variável.
On-Demand é o mais simples: você paga por requisição e o DynamoDB acomoda carga variável automaticamente. É adequado para tráfego imprevisível, produtos em estágio inicial e workloads em rajadas onde você não quer gerenciar metas de capacidade.
Provisioned é planejamento de capacidade: você especifica throughput de leitura e gravação (ou usa auto scaling) e obtém precificação mais previsível em uso estável. Costuma sair mais barato para workloads consistentes e equipes que conseguem prever demanda.
Throughput provisionado é medido em:
O tamanho do item e o padrão de acesso determinam o custo real: itens maiores, consistência forte e scans podem consumir capacidade rapidamente.
O auto scaling ajusta RCUs/WCUs provisionados com base em metas de utilização. Ajuda em crescimento gradual e ciclos previsíveis, mas não é instantâneo. Picos súbitos ainda podem causar throttling se a capacidade não subir rápido o suficiente, e não resolve uma chave de partição quente que concentra tráfego.
DynamoDB Accelerator (DAX) é um cache em memória que pode reduzir latência de leitura e descarregar leituras repetidas (ex.: páginas de produto populares, sessões). É mais útil quando muitos clientes solicitam repetidamente os mesmos itens; não ajuda padrões com muitas escritas e não substitui um bom design de chaves.
O DynamoDB permite que você troque garantias de leitura por latência e custo, então é importante ser explícito sobre o que “correto” significa para cada operação.
Por padrão, GetItem e Query usam leituras eventualmente consistentes: você pode, brevemente, ver um valor mais antigo logo após uma escrita. Isso costuma ser aceitável para feeds, catálogos de produtos e outras visões read-mostly.
Com leituras fortemente consistentes (opção para leituras na tabela base em uma única região), o DynamoDB garante que você verá a última escrita confirmada. Consistência forte custa mais capacidade de leitura e pode aumentar a latência em cauda, então reserve para leituras realmente críticas.
Consistência forte é valiosa para leituras que gateiam ações irreversíveis:
Para contadores, a abordagem mais segura normalmente não é “ler forte e depois escrever”, mas uma atualização atômica (ex.: UpdateItem com ADD) para que incrementos não se percam.
Transações do DynamoDB (TransactWriteItems, TransactGetItems) oferecem semântica ACID para até 25 itens. São úteis quando você precisa atualizar vários itens juntos — como criar um pedido e reservar inventário — ou impor invariantes que não toleram estados intermediários.
Retries são normais em sistemas distribuídos. Faça escritas idempotentes para que retries não dupliquem efeitos:
ConditionExpression (ex.: "only create if attribute_not_exists")Correção no DynamoDB é, em grande parte, escolher o nível certo de consistência e projetar operações para que retries não quebrem os dados.
DynamoDB armazena dados de tabela em múltiplas partições físicas. Cada partição tem throughput finito para leituras e escritas, além de limite no quanto de dados pode armazenar. Sua chave de partição determina onde um item vive; se muitas requisições mirarem o mesmo valor de chave de partição (ou um pequeno conjunto), essa partição vira o gargalo.
Partições quentes geralmente são causadas por escolhas de chave que concentram tráfego: uma chave “global” como USER#1, TENANT#default ou STATUS#OPEN, ou padrões ordenados por tempo onde todos gravam em “agora” sob uma mesma chave.
Normalmente você verá:
ProvisionedThroughputExceededException) para um subconjunto de chavesProjete para distribuição primeiro, depois para conveniência de consulta:
TENANT#<id> em vez de uma constante compartilhada).ORDER#<id>#<shard> para espalhar escritas por N shards e depois consulte através dos shards quando necessário.METRIC#2025-12-22T10) para evitar “todas as escritas indo para o item mais recente”.Para picos imprevisíveis, On-Demand pode absorver rajadas (dentro dos limites do serviço). No modo Provisioned, use auto scaling e implemente backoff exponencial com jitter nos clientes ao enfrentar throttles para evitar retries sincronizados que amplifiquem o pico.
A modelagem no DynamoDB começa por padrões de acesso, não por diagramas ER. Você projeta chaves para que as consultas necessárias se tornem operações rápidas de Query, enquanto o restante é evitado ou tratado assincronamente.
“Design de tabela única” significa armazenar vários tipos de entidade (usuários, pedidos, mensagens) em uma única tabela e usar convenções de chave consistentes para buscar dados relacionados em um único Query. Isso reduz round-trips entre entidades e mantém a latência previsível.
Uma abordagem comum é usar chaves compostas:
PK agrupa uma partição lógica (ex.: USER#123)SK ordena itens dentro desse grupo (ex.: PROFILE, ORDER#2025-12-01, MSG#000123)Isso permite buscar “tudo de um usuário” ou “apenas pedidos de um usuário” escolhendo um prefixo de chave de ordenação.
Para relacionamentos tipo grafo, uma adjacency list funciona bem: armazene arestas como itens.
PK = USER#123, SK = FOLLOWS#USER#456Para suportar consultas reversas ou verdadeiros muitos-para-muitos, adicione um item de aresta invertida ou projete um GSI, dependendo dos caminhos de leitura.
Para eventos e métricas, evite partições sem limite usando bucketização:
PK = DEVICE#9#2025-12-22 (device + dia)SK = TS#1734825600 (timestamp)Use TTL para expirar pontos antigos automaticamente, e mantenha agregados (rollups horários/diários) como itens separados para dashboards rápidos.
Se quiser um aprofundamento nas convenções de chave, veja /blog/partition-key-and-sort-key-design.
DynamoDB Streams é o mecanismo built-in de captura de mudanças (CDC). Quando habilitado em uma tabela, todo insert, update ou delete gera um registro de stream que consumidores downstream podem reagir — sem precisar poll da tabela.
Um registro de stream contém chaves e (opcionalmente) a imagem antiga e/ou nova do item, dependendo do stream view type escolhido (keys only, new image, old image, both). Registros são agrupados em shards, que você lê de forma sequencial.
Uma arquitetura comum é DynamoDB Streams → AWS Lambda, onde cada lote de registros aciona uma função. Outros consumidores também são possíveis (consumidores customizados, ou enviar para sistemas de analytics/log).
Workflows típicos incluem:
Isso mantém a tabela primária otimizada para leituras/escritas de baixa latência enquanto empurra trabalho derivado para consumidores assíncronos.
Streams fornecem processamento ordenado por shard (o que tipicamente se correlaciona com a chave de partição), mas não há ordenação global entre todas as chaves. A entrega é at-least-once, então duplicatas podem ocorrer.
Para lidar com isso com segurança:
Projetado com essas garantias em mente, Streams pode transformar o DynamoDB em uma espinha dorsal sólida para sistemas orientados a eventos.
DynamoDB é projetado para alta disponibilidade espalhando dados por múltiplas Availability Zones dentro de uma região. Para a maioria das equipes, os ganhos práticos de confiabilidade vêm de uma estratégia clara de backup, entender opções de replicação e monitorar as métricas certas.
Backups on-demand são snapshots manuais (ou automatizados) que você tira quando quer um ponto de restauração conhecido — antes de uma migração, após um release ou antes de um grande backfill. São ótimos para “marcar” momentos.
Point-in-time recovery (PITR) captura mudanças continuamente para que você possa restaurar a tabela para qualquer segundo dentro da janela de retenção. PITR é a rede de segurança para deletes acidentais, deploys ruins ou escritas malformadas.
Se precisar de resiliência multi-região ou leituras com baixa latência próximas aos usuários, Global Tables replicam dados entre regiões selecionadas. Elas simplificam planos de failover, mas introduzem delays de replicação cross-region e considerações de resolução de conflitos — mantenha claros padrões de escrita e propriedade de itens.
No mínimo, alerte sobre:
Esses sinais normalmente indicam problemas com partições quentes, capacidade insuficiente ou padrões de acesso inesperados.
Para throttling, primeiro identifique o padrão de acesso que o causa, então mitigue trocando temporariamente para on-demand ou aumentando a capacidade provisionada, e considere shardear chaves quentes.
Para outages parciais ou aumento de erros, reduza o raio de ação: desative tráfego não crítico, faça retries com backoff+jitter e degrade graciosamente (por exemplo, servir leituras em cache) até a tabela se estabilizar.
A segurança no DynamoDB trata majoritariamente de restringir quem pode chamar quais ações de API, de onde e em quais chaves. Como tabelas podem conter muitos tipos de entidade (e às vezes múltiplos tenants), controle de acesso deve ser projetado junto com o modelo de dados.
Comece com políticas IAM baseadas em identidade que limitem ações (ex.: dynamodb:GetItem, Query, PutItem) ao mínimo necessário e escopo para ARNs de tabela específicos.
Para controle mais fino, use dynamodb:LeadingKeys para restringir acesso por valores de chave de partição — útil quando um serviço ou tenant só deve ler/escrever itens no seu próprio keyspace.
DynamoDB criptografa dados em repouso por padrão usando chaves AWS owned ou uma KMS key gerenciada pelo cliente. Se você tem requisitos de compliance, verifique:
Para criptografia em trânsito, garanta que os clientes usem HTTPS (SDKs AWS fazem isso por padrão). Se você termina TLS em um proxy, confirme que o salto entre o proxy e o DynamoDB ainda esteja criptografado.
Use um VPC Gateway Endpoint para DynamoDB para que o tráfego permaneça na rede AWS e você possa aplicar políticas de endpoint para restringir acesso. Combine isso com controles de egress (NACLs, security groups e roteamento) para evitar caminhos que permitam acesso público irrestrito.
Para tabelas compartilhadas, inclua um identificador de tenant na chave de partição (por exemplo, TENANT#<id>), e então faça enforcement de isolamento de tenant com condições IAM em dynamodb:LeadingKeys.
Se precisar de isolamento mais forte, considere tabelas separadas por tenant ou por ambiente, e reserve design de tabela compartilhada quando simplicidade operacional e eficiência de custo compensarem um raio de blast maior.
DynamoDB costuma ser “barato quando você é preciso, caro quando é vago.” Custos seguem seus padrões de acesso, então o melhor trabalho de otimização começa por tornar esses padrões explícitos.
Sua fatura é moldada principalmente por:
Uma surpresa comum: cada escrita na tabela é também uma escrita em cada GSI afetado, então “só mais um índice” pode multiplicar o custo de escrita.
Bom design de chaves reduz a necessidade de operações caras. Se você frequentemente precisa de Scan, está pagando para ler dados que serão descartados.
Prefira:
Query por partition key (e opcionalmente condições na sort key)Se um padrão de acesso é raro, considere servi-lo via tabela separada, job ETL ou um modelo de leitura em cache em vez de um GSI permanente.
Use TTL para deletar automaticamente itens de curta duração (sessions, tokens temporários, estados intermediários). Isso reduz armazenamento e pode manter índices menores ao longo do tempo.
Para dados append-heavy (eventos, logs), combine TTL com designs de sort-key que permitam consultar “apenas recentes”, evitando tocar histórico frio rotineiramente.
No modo provisionado, defina bases conservadoras e escale com auto scaling baseado em métricas reais. No modo on-demand, aten atenção a padrões ineficientes (itens grandes, clientes chatos) que disparam volume de requisições.
trate Scan como último recurso — quando precisar processar a tabela inteira, agende fora de pico ou execute como batch controlado com paginação e backoff.
DynamoDB brilha quando sua aplicação pode ser expressa como um conjunto de padrões de acesso bem definidos e você precisa de latência consistentemente baixa em alta escala. Se você consegue descrever suas leituras e gravações antecipadamente (por chave de partição, chave de ordenação e poucos índices), muitas vezes é uma das formas mais simples de operar um datastore altamente disponível.
DynamoDB é uma escolha forte quando você tem:
Procure outras opções se seus requisitos centrais incluírem:
Muitas equipes mantêm DynamoDB para leituras/escritas “quentes” e adicionam:
Se você está validando padrões de acesso e convenções de tabela única, rapidez importa. Equipes às vezes prototipam o serviço e UI em Koder.ai (uma plataforma que gera apps web, server e mobile a partir de chat) e então iteram no design de chaves do DynamoDB à medida que caminhos de consulta reais emergem. Mesmo que o backend de produção difira, protótipos de ponta a ponta ajudam a revelar quais queries deveriam ser Query e quais se tornariam scans caros.
Valide: (1) suas queries principais são conhecidas e baseadas em chaves, (2) necessidades de correção batem com o modelo de consistência, (3) tamanhos esperados de itens e crescimento estão entendidos, e (4) o modelo de custo (on-demand vs provisionado + autoscaling) cabe no orçamento.
DynamoDB é um banco de dados NoSQL totalmente gerenciado da AWS, projetado para leituras/gravações com latência consistentemente baixa em escalas muito altas. Equipes o adotam quando conseguem definir padrões de acesso baseados em chaves (buscar por ID, listar por proprietário, consultas por intervalo de tempo) e querem evitar operar a infraestrutura do banco de dados.
É especialmente comum em microsserviços, aplicações serverless e sistemas orientados a eventos.
Uma tabela guarda itens (como linhas). Cada item é um conjunto flexível de atributos (como colunas) e pode incluir dados aninhados.
O DynamoDB funciona bem quando uma requisição normalmente precisa “da entidade inteira”, porque itens podem conter maps e lists (estruturas tipo JSON).
Uma chave de partição sozinha identifica um item (chave primária simples). Uma chave composta (chave de partição + chave de ordenação) permite que múltiplos itens compartilhem a mesma chave de partição, sendo unicamente identificados e ordenados pela chave de ordenação.
Chaves compostas habilitam padrões como:
Use Query quando você puder especificar a chave de partição (e opcionalmente uma condição na chave de ordenação). É o caminho rápido e escalável.
Use Scan apenas quando precisar realmente ler tudo; ele percorre toda a tabela ou índice e filtra depois, o que costuma ser mais lento e caro.
Se você estiver fazendo muitos scans, é sinal de que o design de chave ou índice precisa ser revisado.
Índices secundários dão caminhos alternativos de consulta.
Índices aumentam o custo das escritas porque cada escrita na tabela base é replicada nos índices afetados.
Escolha On-Demand se o tráfego for imprevisível, com picos, ou se você não quer gerenciar capacidade. Você paga por requisição.
Escolha Provisioned se o uso for estável/preditível e você quiser custos mais controlados. Combine com auto scaling, lembrando que ele pode não reagir instantaneamente a picos súbitos.
Por padrão, leituras são eventualmente consistentes, o que significa que você pode ver um valor antigo logo após uma escrita.
Use leituras fortemente consistentes (quando disponíveis) para verificações críticas que precisam estar atualizadas, como gates de autorização ou estados de workflow.
Para correção sob concorrência, prefira atualizações atômicas (ex.: escritas condicionais ou ADD) em vez de ciclos ler-modificar-escrever.
Transações (TransactWriteItems, TransactGetItems) fornecem garantias ACID para até 25 itens.
Use-as quando for necessário atualizar múltiplos itens juntos (ex.: criar um pedido e reservar inventário) ou garantir invariantes que não toleram estados parciais.
Elas custam mais e adicionam latência, então reserve para fluxos que realmente exijam essas garantias.
Partições quentes ocorrem quando muitas requisições atingem o mesmo valor de chave de partição (ou um pequeno conjunto de valores), causando throttling mesmo que a tabela esteja ociosa no geral.
Mitigações comuns:
Habilite DynamoDB Streams para obter um fluxo de mudanças em inserts, updates e deletes. Um padrão comum é Streams → Lambda para acionar trabalhos downstream.
Garantias importantes para projetar:
Faça os consumidores (upsert por chave, escritas condicionais, ou controle de IDs de evento processados).