Modellazione dati e chiavi in DynamoDB
Amazon DynamoDB è un database NoSQL key-value/document completamente gestito, con latenza in single-digit millisecond e scaling orizzontale automatico. Il cuore del data modeling è la scelta delle chiavi. La partition key (hash key) determina la partizione fisica in cui l’item viene salvato: serve alta cardinalità e distribuzione uniforme degli accessi per evitare hot partition e throttling. La sort key (range key) è opzionale: insieme alla partition key forma una composite primary key che permette di raggruppare più item sotto la stessa partizione e di interrogarli per intervalli (operatori come begins_with o between sulla sort key).
Preferisci sempre Query (accesso mirato tramite partition key) a Scan, che legge l’intera tabella ed è costosa. Ogni item ha un limite di 400 KB. Per la capacità scegli tra on-demand (traffico imprevedibile o spiky, paghi per richiesta, nessuna pianificazione) e provisioned (traffico prevedibile, definisci RCU/WCU, abbini auto scaling e reserved capacity per ridurre i costi). In caso di ProvisionedThroughputExceededException l’SDK applica retry con exponential backoff e jitter. Le conditional writes (una condizione di esistenza sull’attributo, oppure optimistic locking con un attributo di versione) garantiscono aggiornamenti atomici e prevengono sovrascritture concorrenti. Il TTL fa scadere automaticamente gli item tramite un attributo con timestamp epoch: la cancellazione è best-effort (entro circa 48 ore), non consuma WCU ed è gratuita.
Indici secondari: GSI vs LSI
Gli indici secondari servono a interrogare la tabella con pattern di accesso diversi dalla primary key. Il Local Secondary Index (LSI) mantiene la stessa partition key ma usa una sort key alternativa, va creato contestualmente alla tabella (non è aggiungibile dopo), condivide RCU/WCU con la tabella base e supporta anche le strongly consistent read. Il Global Secondary Index (GSI) può avere partition key e sort key completamente diverse, si crea o elimina in qualsiasi momento, ha capacità propria e offre solo eventually consistent read. In entrambi i casi definisci le projection (KEYS_ONLY, INCLUDE, ALL) per bilanciare costi di storage e attributi disponibili senza risalire alla tabella.
DAX, ElastiCache e il caching
DynamoDB Accelerator (DAX) è una cache in-memory write-through specifica per DynamoDB, con letture a microsecond. È API-compatibile, quindi riduce le modifiche al codice, e serve sia item cache sia query cache. DAX accelera solo le eventually consistent read; le strongly consistent read passano comunque alla tabella. È ideale per workload read-heavy con hot key e vive dentro una VPC.
Amazon ElastiCache (Redis o Memcached) è invece una cache generica per alleggerire database relazionali o carichi di lettura ripetuti. Il pattern più comune è cache-aside (lazy loading): l’app legge dalla cache e, su miss, carica dal DB e la popola; in alternativa write-through aggiorna la cache a ogni scrittura. Il TTL su ogni chiave è fondamentale per evitare dati stale e liberare memoria. Redis aggiunge replica, persistenza, pub/sub e strutture dati avanzate; Memcached è più semplice e multi-thread. A differenza di DAX, ElastiCache richiede logica applicativa esplicita e non è legata a DynamoDB.
Amazon S3 per sviluppatori
Un presigned URL concede accesso temporaneo e a tempo limitato a un singolo oggetto (upload o download) usando le credenziali di chi lo genera, senza rendere pubblico il bucket: perfetto per far caricare o scaricare file direttamente ai client. Per file di grandi dimensioni usa il multipart upload, che divide l’oggetto in parti caricabili in parallelo, migliora resilienza e throughput ed è necessario oltre i 5 GB; le parti incomplete vanno ripulite con una lifecycle rule. S3 offre strong read-after-write consistency.
Trappole tipiche d’esame
- Serve una sort key alternativa dopo aver già creato la tabella → soluzione: usa un GSI, non un LSI: l’LSI si può definire solo alla creazione della tabella.
- Letture a microsecond su DynamoDB senza riscrivere il codice → soluzione: DAX, non ElastiCache; ma ricorda che DAX non accelera le strongly consistent read.
- Far caricare un file al client senza esporre il bucket → soluzione: presigned URL con scadenza breve, non una policy pubblica del bucket.
- Item che devono sparire da soli dopo X giorni → soluzione: DynamoDB TTL (attributo epoch, cancellazione best-effort), non uno Scan periodico con DeleteItem.
- Traffico spiky e imprevedibile → soluzione: capacità on-demand; provisioned + auto scaling conviene solo con pattern prevedibili.
ProvisionedThroughputExceededException/ throttling → soluzione: retry con exponential backoff e jitter e ridistribuisci la partition key, invece di alzare subito la capacità.