Avançado7 min de leitura

Por que um GSI causa throttling nas escritas da tabela base no DynamoDB

Você escreve na sua tabela. A escrita falha com uma exceção de throughput — mas a exceção nomeia um Global Secondary Index, não a tabela. A tabela tem capacidade sobrando.

Vindo do SQL, isso não faz sentido: um índice secundário não pode bloquear um INSERT. No DynamoDB ele pode, e o mecanismo se chama back-pressure de GSI.

Por que um GSI causa throttling nas escritas da tabela base no DynamoDB?

O DynamoDB faz throttling da escrita na tabela base porque cada escrita também é replicada para cada GSI, e se uma partição do GSI não consegue absorver sua parcela, o DynamoDB aplica back-pressure para impedir que o índice fique permanentemente para trás. Então um GSI subprovisionado ou com uma chave de baixa cardinalidade vira um teto rígido para a sua taxa de escrita na tabela base.

  • Uma escrita na tabela base também escreve em cada GSI. Se um GSI não consegue absorver sua parcela, o DynamoDB faz throttling da escrita na tabela base para impedir que o índice fique permanentemente para trás. (documentação AWS)
  • Uma tabela base equilibrada não te salva. O GSI é particionado pela própria chave. Uma chave de GSI de baixa cardinalidade (como status) cria uma partição de índice quente mesmo quando as escritas na tabela base estão perfeitamente espalhadas.
  • A exceção mente sobre a vítima. O ResourceArn aponta para o GSI; a operação que de fato está sofrendo throttling é a sua escrita na tabela.
  • A correção é capacidade ou design da chave, não loops de retry — aumente o throughput do GSI, ou escolha uma chave de partição de GSI que espalhe.

Como uma única escrita toca o índice

Um PutItem na tabela base não é uma escrita só. O DynamoDB replica os atributos projetados do item em cada GSI de forma assíncrona, num modelo eventualmente consistente. Uma escrita lógica se desdobra em N escritas físicas — tabela mais cada índice.

Essa replicação não é gratuita nem opcional. O GSI precisa acompanhar, ou o índice se afasta cada vez mais da tabela a cada operação.

Para deter esse afastamento, o DynamoDB aplica back-pressure: faz throttling da escrita de origem para que o índice nunca fique desatualizado de forma ilimitada.

Então a capacidade de escrita do GSI é um teto rígido para a sua taxa de escrita na tabela base — mesmo que você nunca escreva no GSI diretamente.

Um exemplo prático: uma tabela de pedidos

Digamos que você administre uma tabela de pedidos. O item base:

fieldvaluenote
PK"CUST#8841"partition key
SK"ORD#2026-06-23#A7"sort key
order_state"PROCESSING"
warehouse"EU-MAD-2"
total_cents4990

As escritas na tabela base estão saudáveis. CUST#... tem alta cardinalidade, então as escritas de pedidos se espalham uniformemente pelas partições base. Sem chave quente, capacidade de sobra.

Agora você adiciona um GSI para responder "mostre-me todo pedido em um dado estado":

GSI: orders-by-state
fieldvaluenote
GSI-PKorder_state"PENDING" | "PROCESSING" | "SHIPPED" | "CANCELED"
GSI-SKSK

Quatro valores possíveis de chave de partição. Durante uma promoção relâmpago, quase todo pedido novo cai em order_state = "PENDING". Cada uma dessas escritas acerta a mesma partição do GSI.

Essa partição tem um limite de throughput por partição, e você acabou de mirar toda a sua tempestade de escrita nela.

A tabela base está bem. A partição PENDING do GSI está pegando fogo. O DynamoDB faz throttling do PutItem da tabela base para proteger o índice.

O fluxo que te morde

Eis o caminho do back-pressure — escrita base equilibrada, escrita de índice concentrada:

PutItemorder_state=PENDINGTabela baseespalhada por CUST#Replicação assíncronapara o GSIPartição do GSIPENDING (quente)Limite da partiçãoexcedidoThrottle na escritada BASE

O throttle viaja para trás: uma partição quente do GSI rejeita a escrita da tabela base que a alimentou.

Leia a exceção, não o seu instinto

O tipo da exceção te diz exatamente qual teto você atingiu. O ResourceArn nomeia o GSI; a operação sofrendo throttling ainda é a escrita na tabela.

ModoCódigo de motivoO que acabou
ProvisionadoIndexWriteProvisionedThroughputExceededCapacidade de escrita provisionada do GSI
ProvisionadoIndexWriteKeyRangeThroughputExceededUma única partição quente do GSI
On-demandIndexWriteMaxOnDemandThroughputExceededTeto máximo on-demand configurado do GSI
On-demandIndexWriteAccountLimitExceededLimite de throughput da conta/região

Fonte: Understanding GSI write throttling and back pressure.

O motivo KeyRange é a pista para o caso de partição quente acima: a capacidade geral do GSI pode parecer ok enquanto um intervalo de chave está saturado.

Como corrigir

Dê espaço ao GSI. A causa mais simples é o subprovisionamento. Um GSI tem sua própria capacidade de leitura e escrita, totalmente separada da tabela — veja GSI vs LSI.

Se você provisionou a tabela com generosidade e deixou o GSI magro, aumente a capacidade de escrita do GSI (ou seu máximo on-demand).

Conserte a chave de partição. Capacidade não salva uma chave de baixa cardinalidade — você não consegue superprovisionar uma única partição quente. Escolha uma chave de partição de GSI que espalhe.

Componha-a: order_state#shard onde shard é um pequeno sufixo aleatório, ou inclua a data (PENDING#2026-06-23). As escritas se espalham pelas partições e você ainda faz Query de um estado consultando os shards.

Projete menos atributos. Cada escrita no GSI copia os atributos projetados. Uma projeção KEYS_ONLY ou um INCLUDE enxuto significa escritas de índice menores e menos pressão do que ALL. Não projete o que você nunca vai ler do índice.

Descarte o GSI se ele for só para relatórios. Se "pedidos por estado" é uma pergunta administrativa ocasional, não um caminho quente, um scan periódico com filtro pode vencer um índice permanentemente quente — pese contra Query vs Scan.

Quando você for consultar esse índice, o Expression Builder escreve a KeyConditionExpression para você — ex.: #s = :state AND begins_with(SK, :prefix) — com os nomes e valores escapados corretamente:

KeyConditionExpression     "#s = :state"
ExpressionAttributeNames   { "#s": "order_state" }
ExpressionAttributeValues  { ":state": { "S": "PENDING" } }

A armadilha a lembrar

O instinto relacional — "índices só deixam as escritas um pouco mais lentas" — não se transfere. Um GSI do DynamoDB é uma dependência de throughput, não uma estrutura passiva. Subdimensione-o ou escolha uma chave que se aglomera, e ele faz back-pressure na tabela que serve.

Observe o ConsumedWriteCapacityUnits e o ThrottledRequests do GSI por partição, não só os da tabela.

Próximos passos

  • GSI vs LSI — por que um GSI tem sua própria capacidade e uma chave de partição diferente.
  • Single-table design — sobrecarregando um GSI para servir muitos padrões sem multiplicar índices quentes.
  • Query vs Scan — quando um índice não vale o custo de escrita.

Experimente o DynoTable para observar a capacidade consumida e os eventos de throttle de um GSI contra suas próprias tabelas antes que uma promoção as deixe vermelhas.

Atualizado