Avanzato7 min di lettura

Perché un GSI va in throttling sulle scritture della tabella base in DynamoDB

Scrivi sulla tua tabella. La scrittura fallisce con un'eccezione di throughput — ma l'eccezione nomina un Global Secondary Index, non la tabella. La tabella ha capacità libera.

Venendo da SQL, è un controsenso: un indice secondario non può bloccare un INSERT. In DynamoDB può, e il meccanismo si chiama back-pressure del GSI.

Perché un GSI di DynamoDB va in throttling sulle scritture della tabella base?

DynamoDB mette in throttling la scrittura della tabella base perché ogni scrittura viene replicata anche su ciascun GSI e, se una partizione del GSI non riesce ad assorbire la propria quota, DynamoDB applica back-pressure per impedire all'indice di restare permanentemente indietro. Quindi una chiave di GSI sotto-provisioned o a bassa cardinalità diventa un tetto rigido sul tasso di scrittura della tua tabella base.

  • Una scrittura sulla tabella base scrive anche su ogni GSI. Se un GSI non riesce ad assorbire la sua quota, DynamoDB va in throttling sulla scrittura della tabella base per impedire all'indice di restare permanentemente indietro. (AWS docs)
  • Una tabella base uniforme non ti salva. Il GSI è partizionato dalla propria chiave. Una chiave di GSI a bassa cardinalità (come status) crea una hot index partition anche quando le scritture della tabella base sono distribuite perfettamente.
  • L'eccezione mente sulla vittima. Il ResourceArn punta al GSI; l'operazione che viene effettivamente messa in throttling è la tua scrittura sulla tabella.
  • La soluzione è capacità o design della chiave, non loop di retry — alza il throughput del GSI, oppure scegli una chiave di partizione del GSI che distribuisca.

Come una singola scrittura tocca l'indice

Un PutItem sulla tabella base non è una sola scrittura. DynamoDB replica gli attributi proiettati dell'Item in ogni GSI in modo asincrono, con un modello eventualmente coerente. Una scrittura logica si distribuisce in N scritture fisiche — tabella più ogni indice.

Quella replica non è gratuita né opzionale. Il GSI deve stare al passo, oppure l'indice si allontana ulteriormente dalla tabella a ogni operazione.

Per fermare quella deriva, DynamoDB applica back-pressure: mette in throttling la scrittura sorgente così l'indice non diventa mai illimitatamente obsoleto.

Quindi la write capacity del GSI è un tetto rigido sul tuo tasso di scrittura della tabella base — anche se non scrivi mai direttamente sul GSI.

Un esempio pratico: una tabella ordini

Diciamo che gestisci una tabella ordini. L'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

Le scritture della tabella base sono in salute. CUST#... ha alta cardinalità, quindi le scritture degli ordini si distribuiscono uniformemente tra le partizioni base. Nessuna hot key, capacità abbondante.

Ora aggiungi un GSI per rispondere a "mostrami ogni ordine in un dato stato":

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

Quattro possibili valori di chiave di partizione. Durante una vendita flash, quasi ogni nuovo ordine finisce in order_state = "PENDING". Ognuna di quelle scritture colpisce la stessa partizione del GSI.

Quella partizione ha un limite di throughput per partizione, e hai appena puntato l'intera tempesta di scritture su di essa.

La tabella base sta bene. La partizione PENDING del GSI è in fiamme. DynamoDB mette in throttling il PutItem della tabella base per proteggere l'indice.

Il flusso che ti morde

Ecco il percorso del back-pressure — scrittura base bilanciata, scrittura indice concentrata:

PutItemorder_state=PENDINGTabella basedistribuita per CUST#Replica asyncal GSIPartizione GSIPENDING (calda)Limite partizionesuperatoThrottling sullascrittura BASE

Il throttling viaggia all'indietro: una hot partition del GSI rifiuta la scrittura della tabella base che l'ha alimentata.

Leggi l'eccezione, non l'istinto

Il tipo di eccezione ti dice esattamente quale tetto hai raggiunto. Il ResourceArn nomina il GSI; l'operazione in throttling è comunque la scrittura sulla tabella.

ModalitàReason codeCosa si è esaurito
ProvisionedIndexWriteProvisionedThroughputExceededWrite capacity provisioned del GSI
ProvisionedIndexWriteKeyRangeThroughputExceededUna singola hot partition del GSI
On-demandIndexWriteMaxOnDemandThroughputExceededTetto on-demand max configurato del GSI
On-demandIndexWriteAccountLimitExceededConfine di throughput account/region

Fonte: Understanding GSI write throttling and back pressure.

Il motivo KeyRange è l'indizio rivelatore del caso hot-partition di sopra: la capacità complessiva del GSI può sembrare a posto mentre un range di chiavi è saturo.

Come risolverlo

Dai spazio al GSI. La causa più semplice è il sotto-provisioning. Un GSI ha la propria read e write capacity, del tutto separata dalla tabella — vedi GSI vs LSI.

Se hai provisionato la tabella generosamente e lasciato il GSI scarno, alza la write capacity del GSI (o il suo max on-demand).

Correggi la chiave di partizione. La capacità non salverà una chiave a bassa cardinalità — non puoi out-provisionare una singola hot partition. Scegli una chiave di partizione del GSI che distribuisca.

Componila: order_state#shard dove shard è un piccolo suffisso casuale, oppure incorpora la data (PENDING#2026-06-23). Le scritture si distribuiscono tra le partizioni e puoi comunque fare una Query su uno stato interrogando gli shard.

Proietta meno attributi. Ogni scrittura del GSI copia gli attributi proiettati. Una proiezione KEYS_ONLY o INCLUDE stretta significa scritture dell'indice più piccole e meno pressione rispetto a ALL. Non proiettare ciò che non leggerai mai dall'indice.

Elimina il GSI se serve solo per reporting. Se "ordini per stato" è una domanda admin occasionale, non un percorso caldo, uno scan periodico con un filtro può battere un indice permanentemente caldo — pesalo contro Query vs Scan.

Quando interroghi quell'indice, l' Expression Builder scrive la KeyConditionExpression per te — es. #s = :state AND begins_with(SK, :prefix) — con nomi e valori escapati correttamente:

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

La trappola da ricordare

L'istinto relazionale — "gli indici rallentano le scritture solo un po'" — non si trasferisce. Un GSI di DynamoDB è una dipendenza di throughput, non una struttura passiva. Sottodimensionalo o scegli una chiave che si accalca, e fa back-pressure sulla tabella che serve.

Osserva i ConsumedWriteCapacityUnits e i ThrottledRequests del GSI per partizione, non solo quelli della tabella.

Prossimi passi

  • GSI vs LSI — perché un GSI ha la propria capacità e una chiave di partizione diversa.
  • Single-table design — sovraccaricare un GSI per servire molti pattern senza moltiplicare gli indici caldi.
  • Query vs Scan — quando un indice non vale il suo costo di scrittura.

Prova DynoTable per osservare la capacità consumata di un GSI e gli eventi di throttle sulle tue tabelle prima che una vendita le faccia diventare rosse.

Aggiornato