Avanzato7 min di lettura

Come funzionano gli internals di storage di DynamoDB

DynamoDB è una hash table i cui valori sono alberi ordinati, distribuiti tra le macchine in tre Availability Zone. Due strutture dati fanno quasi tutto il lavoro: un hash sulla partition key sceglie una macchina, un B-tree sulla sort key ordina gli item al suo interno.

Come archivia i dati DynamoDB?

DynamoDB archivia i tuoi dati come una gigantesca hash table distribuita i cui valori sono B-tree ordinati. Un hash sulla sceglie un nodo di storage; un B-tree ordina gli item per sort key al suo interno. Ogni scrittura replica in modo sincrono su tre nodi in tre Availability Zone prima di confermare.

  • La partition key viene hashata, non cercata. DynamoDB esegue una funzione di hash sulla tua PK per trovare l'unico nodo di storage che contiene quella partizione — un salto O(1), a prescindere dalla dimensione della tabella.
  • La sort key vive in un B-tree. Dentro una partizione, gli item sono memorizzati in un B-tree ordinato lessicograficamente per SK, ed è per questo che le letture per range (begins_with, between) sono economiche e lo Scan no.
  • Ogni scrittura colpisce tre nodi prima di confermare. Una scrittura va a un leader, che replica in modo sincrono a due peer in altre AZ — la durabilità è pagata prima che il tuo PutItem ritorni.
  • È per questo che esistono le regole degli access pattern. Hash-poi-albero è veloce solo quando leggi per chiave. Niente chiave, niente percorso veloce — ripieghi sulla scansione dell'albero.

Inizia dalla struttura dati, non dall'API

Venendo da SQL, immagini una tabella come righe su disco con un query planner che sceglie gli index. DynamoDB non ha planner. Il layout di storage è il contratto — cosa è veloce e cosa è un footgun cadono entrambi direttamente da due strutture.

Immagina una gigantesca mappa distribuita. La chiave è un hash della tua partition key. Il valore non è un singolo item — è un intero B-tree di item che condividono quella partition key, ordinati per sort key.

Tutto il resto — la semantica delle query, gli avvisi sui 10 GB, perché una chiave mancante forza uno Scan — è una conseguenza di quell'unica frase.

Fai l'hash della partition key per trovare il nodo

Quando arriva una richiesta, DynamoDB applica una funzione di hash interna al valore della partition key. L'hash mappa in modo deterministico a un nodo di storage — la partizione fisica che possiede quegli item. AWS lo documenta come il meccanismo dietro le ricerche per chiave a tempo costante, a prescindere dalla dimensione della tabella.

Quello è il passo O(1). Una tabella da 10 TB e una da 10 KB costano lo stesso da localizzare: hash, salto, fatto. Non c'è scansione di index per trovare il nodo, niente statistiche, niente piano.

Il trucco è il rovescio della medaglia. Se non fornisci la partition key, DynamoDB non ha alcun nodo a cui saltare — deve percorrere ogni partizione. Quello è uno Scan, ed è la differenza tra O(1) e leggere l'intera tabella.

PutItem / GetItemPK=DEVICE#a91Hash(PK)Nodo di storage(una partizione)B-tree sulla SKREADING#... ordinatoItem

La richiesta fa l'hash su esattamente una partizione, poi discende il B-tree di sort key di quella partizione fino all'item — due passi economici invece di una scansione della tabella.

Ordina gli item in un B-tree per-partizione

Dentro una singola partizione, gli item non sono un heap. Sono tenuti in un B-tree con chiave la sort key, ordinati lessicograficamente. Una ricerca in un B-tree è O(log n), e cosa cruciale quell'n sono gli item in una partizione, non l'intera tabella.

È l'intera ragione per cui le letture per range di sort key sono economiche. Prendi una tabella di telemetria di flotta dove le letture di ogni dispositivo vivono sotto un'unica partition key:

PKSK
PK = DEVICE#a91SK = READING#2026-06-23T08:00Z
PK = DEVICE#a91SK = READING#2026-06-23T08:05Z
PK = DEVICE#a91SK = READING#2026-06-23T08:10Z

Poiché il B-tree è ordinato, "tutte le letture tra le 08:00 e le 09:00" è una discesa dell'albero fino al valore di partenza più una camminata sequenziale — non un filtro su ogni lettura che il dispositivo abbia mai inviato. Leggi solo il range corrispondente.

Quell'ordinamento è anche perché una query begins_with(SK, "READING#2026-06-23") è veloce mentre filtrare su un attributo non-chiave non lo è. L'albero può fare il seek per SK; non può fare il seek per nient'altro. Per comporre quelle condizioni di chiave in sicurezza, costruiscile nell'Expression Builder per DynamoDB invece di concatenare stringhe a mano:

KeyConditionExpression  PK = :pk AND begins_with(SK, :day)

Replica ogni scrittura su tre AZ

Una partizione non è una sola macchina. Ognuna è replicata su tre nodi in tre Availability Zone — una discendenza di design che risale al modello di replica del paper Amazon Dynamo del 2007.

Un nodo è il leader per la partizione. Una scrittura va al leader, che scrive localmente e replica ai suoi due peer. Il leader conferma la scrittura una volta che un quorum durevole di nodi la possiede — così la durabilità tra le AZ è pagata prima che il tuo PutItem ritorni.

Le letture hanno una scelta. Una lettura fortemente coerente va al leader e vede l'ultima scrittura committata. Una lettura eventualmente coerente può essere servita da uno qualsiasi dei tre nodi, uno dei quali può essere indietro di qualche millisecondo — è il ritardo che scambi per letture più economiche e più disponibili.

Eventualmente coerenteFortemente coerente
Servita daUno dei 3 nodiSolo il nodo leader
Vede l'ultima scritturaForse (piccolo ritardo)Sempre
Costo RCUMetàPieno
DisponibilitàPiù altaPiù bassa (nodo singolo)

La stessa idea di propagazione async è perché una lettura su un GSI può essere stantia — vedi i GSI sono eventualmente coerenti.

Leggi le regole dalla struttura

Quasi ogni "regola" di DynamoDB è solo fisica dello storage:

  • Fornisci sempre la partition key. Niente chiave, niente bersaglio per l'hash — stai scansionando l'intera mappa. È il cuore di Query vs Scan.
  • Co-localizza ciò che leggi insieme sotto un'unica partition key, così che un singolo hash + camminata dell'albero restituisca l'intera item collection. È la fondazione del single-table design.
  • Mantieni le partizioni limitate. Una partizione è un B-tree su un insieme finito di nodi; una hot key fuori controllo o il tetto di 10 GB di un LSI sono entrambi limiti di quella partizione fisica.

Una volta che vedi la forma hash-poi-B-tree, la disciplina degli access pattern smette di sembrare arbitraria — stai solo tenendo ogni lettura sul percorso veloce.

Prossimi passi

Modella le tue chiavi per corrispondere alla struttura con strategie per le sort key e single-table design, poi assembla le espressioni effettive nell'Expression Builder per DynamoDB. Prova DynoTable per guardare queste letture eseguirsi sulle tue tabelle e vedere esattamente quali item una condizione di chiave riporta indietro.

Aggiornato