⚡ DynamoDB – Base NoSQL (AWS), Clés & Performance
Guide complet IDEO-Lab sur la base de données NoSQL managée d'AWS (Clé-Valeur/Document).
Concept : NoSQL Managé
AWS, NoSQL (Clé-Valeur & Document), Sans Serveur.
AWS NoSQL Serverlessvs. SQL (RDS)
Scalabilité (Horizontale vs Verticale), Schéma (Flexible).
SQL NoSQLModèle de Données
Tables, Items (Documents), Attributs (Scalaires, JSON).
Table Item AttributClé Primaire (PK)
Le concept central. Simple ou Composite.
Primary Key (PK)Clé Simple : Partition Key
Clé de Hachage (PK). (Unique). Haute cardinalité.
Clé Composite (PK+SK)
Partition Key (PK) + Sort Key (SK). (Requêtes 1-N).
Débit (Throughput)
Provisionné vs On-Demand (À la demande).
Provisioned On-DemandRCU (Read Capacity Unit)
Unités de Capacité de Lecture (4KB, Strong vs Eventual).
RCU EventualWCU (Write Capacity Unit)
Unités de Capacité d'Écriture (1KB).
WCU ÉcritureProblème : Accès (Query/Scan)
Query (PK/SK) vs Scan (Lent, Coûteux).
Query ScanIndex : LSI
Local Secondary Index (Même PK, SK différent).
LSI LocalIndex : GSI (Crucial)
Global Secondary Index (PK/SK différents). (La "Vue" SQL).
GSI GlobalOpérations (Item)
GetItem, PutItem, UpdateItem, DeleteItem.
Opérations (Lecture)
Query (PK) vs Scan (Tout).
Outils (CLI & SDK)
AWS CLI (aws dynamodb), SDK (Boto3).
Cache : DAX
DynamoDB Accelerator (Cache In-Memory managé).
DAX CacheStreams (Flux)
Flux d'événements (CDC) (Insert/Update/Delete).
Streams CDC LambdaTTL (Time To Live)
Expiration automatique des items (sessions, logs).
TTL ExpirationLe Service "Flagship" Serverless NoSQL d'AWS
Amazon DynamoDB est un service de base de données NoSQL (non relationnel), entièrement managé (fully managed). C'est le choix par défaut pour les applications "cloud-native" qui nécessitent une latence extrêmement faible et une scalabilité massive, sans aucune gestion de serveur.
Il supporte les modèles Clé-Valeur (Key-Value) et Document (JSON), mais son architecture est optimisée pour des accès (lectures/écritures) très rapides basés sur des clés primaires (voir 2.1).
Avantages Business & TCO (Coût Total de Possession)
- Performance Garantie (SLA) : DynamoDB est conçu pour une latence constante à un chiffre (single-digit millisecond), que la table contienne 1 Go ou 500 To de données. (RDS/SQL ne peut pas garantir cela).
- Scalabilité "Infinie" : La scalabilité est horizontale. En mode "On-Demand", le service absorbe les pics de trafic (de 0 à 100 000 requêtes/sec) sans intervention manuelle.
- Zéro Administration (Serverless) : C'est l'argument n°1.
- Pas de serveurs (EC2/VM) à provisionner.
- Pas d'OS à patcher (sécurité).
- Pas de réplication Multi-AZ (Haute Disponibilité) à configurer.
- Pas de "sharding" manuel à gérer.
- Applications Globales : Via les "Global Tables", DynamoDB offre une réplication multi-région, active-active, en quelques clics, pour des applications à faible latence mondiale.
Cas d'Usage Stratégiques
On choisit DynamoDB lorsque la vitesse et la scalabilité des accès (basés sur une clé) sont plus importantes que la flexibilité des requêtes (SQL JOIN).
| Cas d'Usage | Exemple d'accès (PK/SK) |
|---|---|
| E-commerce | Paniers (SessionID), Profils Clients (UserID). |
| Jeux Vidéo | Classements (GameID + Score), États de joueurs (PlayerID). |
| IoT / Télémétrie | Ingestion massive de données (DeviceID + Timestamp). |
| Ad-Tech (Publicité) | Comptage temps-réel (AdID), Profils (CookieID). |
| SaaS / Métadonnées | Stockage des métadonnées utilisateur (TenantID + UserID). |
Il est très courant d'utiliser DynamoDB (pour la vitesse) en complément de RDS/SQL (pour les relations complexes) ou OpenSearch (pour la recherche textuelle).
Choisir DynamoDB (NoSQL) plutôt que RDS (MySQL/Postgres) est une décision d'architecture fondamentale.
| Critère | DynamoDB (NoSQL) | RDS (SQL Relationnel) |
|---|---|---|
| Modèle de Données | Flexible (Clé-Valeur / JSON). Schéma non-rigide. | Rigide (Schéma). Tables, Colonnes, Types définis. |
| Relations | Non (Dénormalisé). Pas de JOIN. (On duplique les données). | Oui (Relations). JOIN, Clés étrangères (FK), Normalisation. |
| Scalabilité | Horizontale (Scales Out). (Ajoute des partitions/serveurs). Illimitée. | Verticale (Scales Up). (Augmenter CPU/RAM). Limité. |
| Performance | Latence constante (milliseconde), peu importe la taille. | Latence variable (dépend des JOIN, index, taille). |
| Requêtes | Limitées (GetItem, Query, Scan). L'accès (Query) doit utiliser la Clé Primaire. | Flexibles (SELECT * WHERE... JOIN...). (WHERE sur n'importe quelle colonne). |
| Cas d'Usage | Trafic massif (IoT, Jeux), Caching, Catalogues. | Données complexes (Finance, ERP), BI, "Tout le reste". |
La terminologie de DynamoDB (NoSQL) vs SQL.
| DynamoDB (NoSQL) | SQL (Relationnel) |
|---|---|
| Table | Table |
| Item | Row (Ligne) |
| Attribut | Column (Colonne) |
Schéma Flexible
Une Table (ex: "Users") contient des Items (Documents JSON). Chaque Item doit avoir la Clé Primaire (PK) (ex: UserID).
En dehors de la PK, les Attributs (colonnes) peuvent être totalement différents d'un item à l'autre.
(Table: "Users")
Item 1 (PK: "user-100") {
"UserID": "user-100",
"Email": "alice@example.com",
"Age": 30
}
Item 2 (PK: "user-101") {
"UserID": "user-101",
"Email": "bob@example.com",
"Adresse": { // (Attribut complexe : Map/JSON)
"Rue": "123 Main St",
"Ville": "Paris"
},
"Tags": [ "admin", "dev" ] // (Attribut : Set/Liste)
}
C'est le concept le plus important de DynamoDB. C'est la seule chose (avec les Index) sur laquelle vous pouvez faire des requêtes (Query) efficaces.
Le choix de la Clé Primaire (PK) définit votre modèle d'accès (Access Pattern) et la scalabilité de votre table. (Si vous choisissez mal, la table est inutilisable).
La PK doit être unique pour chaque Item.
Il existe deux types de Clés Primaires :
- Clé Simple (Simple Key) : (Voir 2.2)
- Composée uniquement d'une Partition Key (PK).
- Usage : Stockage Clé-Valeur pur (ex: table de sessions).
- Clé Composite (Composite Key) : (Voir 2.3)
- Composée d'une Partition Key (PK) ET d'une Sort Key (SK) (Clé de Tri).
- Usage : Modélisation 1-N (ex: Utilisateur -> Commandes).
La Clé de Partition (Partition Key / PK) (aussi appelée "Hash Key") est l'identifiant unique d'un Item (si Clé Simple).
Rôle (La Distribution)
DynamoDB est un système distribué (des milliers de serveurs/partitions). Quand vous écrivez un Item, DynamoDB passe la valeur de la PK (ex: "user-100") dans une fonction de hachage (Hash).
Le résultat du "hash" détermine sur quelle partition physique (serveur) l'Item sera stocké.
hash("user-100") -> 1234 -> [ Partition A ]
hash("user-101") -> 5678 -> [ Partition B ]
hash("user-102") -> 1235 -> [ Partition A ]
Haute Cardinalité (Critique)
Problème (Hot Partition) : Si vous choisissez une mauvaise PK (faible cardinalité), ex: "TypeDeProduit" (Livre, DVD, Jeu), tous les "Livres" (10 millions) iront sur la même partition, créant un goulot d'étranglement (Hot Partition).
Règle : La PK doit avoir une Haute Cardinalité (ex: UserID, SessionID, OrderID) pour distribuer (spray) la charge uniformément.
C'est le modèle le plus puissant. La Clé Primaire est composée de deux attributs :
- Partition Key (PK) : La clé de hachage (définit la partition).
- Sort Key (SK) (Clé de Tri) : (Aussi appelée "Range Key").
Fonctionnement (Requêtes 1-N)
L'unicité de l'Item est la combinaison (PK + SK). (Vous pouvez avoir plusieurs Items avec la même PK, tant que la SK est différente).
Sur la partition (définie par la PK), les Items sont stockés physiquement triés (Sorted) par la Sort Key.
Exemple (Table Commandes)
PK (UserID) | SK (Timestamp) | Data... |
|---|---|---|
| User_A | 2025-01-10T10:00 | {Cmd: 123, ...} |
| User_A | 2025-01-15T11:00 | {Cmd: 124, ...} |
| User_A | 2025-02-01T12:00 | {Cmd: 125, ...} |
| User_B | 2025-01-12T09:00 | {Cmd: 126, ...} |
Usage (Query)
Permet des requêtes (Query) très efficaces (au lieu d'un Scan) :
- "Donne-moi toutes les commandes pour
UserID = User_A" (Cible la partition) - "Donne-moi toutes les commandes pour
UserID = User_AETTimestamp > 2025-01-12" (Utilise la clé de tri)
DynamoDB (Serverless) facture la performance (Débit/Throughput) selon deux modèles :
1. Provisioned Mode (Mode Provisionné)
(Le modèle "classique").
Vous spécifiez (provisionnez) à l'avance la capacité de lecture (RCU) et d'écriture (WCU) que vous souhaitez (ex: 10 RCU, 5 WCU).
Facturation : Vous payez pour cette capacité, que vous l'utilisiez ou non (facturation à l'heure).
Avantage : Coût prévisible. Moins cher si le trafic est stable et prévisible. (Peut utiliser "Auto-Scaling").
Inconvénient : Si le trafic dépasse la capacité (Spike), DynamoDB rejette (throttle) les requêtes (ProvisionedThroughputExceededException).
2. On-Demand Mode (À la Demande)
(Le modèle "moderne" / Serverless pur).
Vous ne provisionnez rien. DynamoDB scale (monte et descend) instantanément pour gérer le trafic (de 0 à 40 000 RPS).
Facturation : Vous payez par million de requêtes (R/W) réellement exécutées.
Avantage : Zéro gestion (pas de throttling). Idéal pour trafic imprévisible ou "spiky".
Inconvénient : Coût imprévisible. (Plus cher que "Provisionné" si le trafic est stable).
Unité de mesure pour la Lecture (en mode Provisionné).
Eventual Consistency (Cohérence à Terme)
1 RCU = 2 lectures/seconde (jusqu'à 4KB par lecture)
(Par défaut). Lecture la plus rapide. Ne garantit pas de lire la toute dernière écriture (peut avoir < 1 sec de retard).
Exemple : Un item de 10 KB.
- (10 KB / 4 KB) = 2.5 -> Arrondi à 3 "blocs".
- 3 blocs / 2 (par RCU) = 1.5 -> Arrondi à 2 RCU (pour 1 lecture/sec).
Strong Consistency (Cohérence Forte)
1 RCU = 1 lecture/seconde (jusqu'à 4KB par lecture)
(Optionnel, 2x plus cher). Garantit que la lecture retourne toujours la dernière écriture validée (Commit).
Exemple : Un item de 10 KB.
- (10 KB / 4 KB) = 2.5 -> Arrondi à 3 "blocs".
- 3 blocs / 1 (par RCU) = 3 RCU (pour 1 lecture/sec).
Unité de mesure pour l'Écriture (en mode Provisionné).
Calcul (WCU)
1 WCU = 1 écriture/seconde (jusqu'à 1KB par écriture)
(L'écriture est toujours "forte" (Strongly Consistent)).
Exemple : Écrire un item de 3.5 KB.
- (3.5 KB / 1 KB) = 3.5 -> Arrondi à 4 "blocs".
- 4 WCU (pour 1 écriture/sec).
DynamoDB n'a que 2 méthodes de lecture (en dehors de GetItem) :
Query (Requête)
(Rapide, Efficace, Recommandé)
Une Query vous oblige à fournir la Clé de Partition (PK) exacte.
Ex : WHERE UserID = 'User_A'.
DynamoDB utilise le hash (2.2) pour sauter directement à la bonne partition (serveur) et lire les données (très rapide).
Problème : Que faire si je veux "Trouver tous les utilisateurs dont la Ville == 'Paris'" ? (La Ville n'est pas la PK).
Scan (Scan)
(Lent, Coûteux, À ÉVITER)
Un Scan lit chaque Item (ligne) de la table entière, puis applique un filtre (ex: Ville == 'Paris') (l'équivalent d'un "Full Table Scan" en SQL, mais pire).
Coût : Si votre table fait 1 To, un Scan lit 1 To. Vous payez (en RCU) pour toutes les données lues, pas seulement celles retournées.
Solution : Créer un Index (GSI) (4.3).
Un LSI est un index qui permet un tri alternatif des données, mais à l'intérieur de la même partition.
Structure (LSI)
- PK : Doit être la même que la table de base.
- SK : Doit être un attribut différent de la table de base.
Exemple (Table Commandes)
Table de Base :
PK: UserID | SK: OrderID (Trié par ID Commande)
LSI :
PK: UserID | SK: Date (Trié par Date)
Usage (Query)
Permet de nouvelles requêtes (Query) :
- (Base) "Donne-moi les commandes 123 et 124 pour User_A".
- (LSI) "Donne-moi les commandes pour User_A, triées par Date".
Limitations : Ne peut être créé qu'à la création de la table. Partage le débit (RCU/WCU) de la table de base. Ne résout pas le problème du "Hot Partition".
Le GSI est la solution au problème du Scan (4.1). C'est l'outil n°1 pour modéliser des accès secondaires.
Un GSI est (conceptuellement) une nouvelle table (copie), gérée automatiquement par DynamoDB, mais avec une Clé Primaire (PK/SK) différente.
Exemple (Résoudre "Scan par Ville")
Table de Base (Users) :
PK: UserID | Email | Ville
(Problème : "Trouver les users par Ville" -> Scan)
On crée un GSI (ex: GSI_Ville) :
PK (GSI): Ville | SK (GSI): UserID
Fonctionnement (Async)
- Vous écrivez (
PutItem) sur la Table de Base. - DynamoDB (asynchronement) copie les données (PK, SK, Attributs projetés) dans la table GSI (Cohérence à terme / Eventual Consistency).
Usage (Query)
Vous pouvez maintenant faire une Query (rapide) sur le GSI :
Query (Index: GSI_Ville) WHERE Ville = "Paris"
Coût : Un GSI a ses propres RCU/WCU provisionnés (ou On-Demand). Il double (au minimum) le coût d'écriture.
Opérations de base (CRUD) qui ciblent un seul Item (via sa PK/SK complète).
| Opération | Description |
|---|---|
GetItem | Lecture (READ) d'un seul Item (par sa PK/SK). (Très rapide). |
PutItem | Écriture (CREATE/UPDATE). Écrase l'Item s'il existe, ou le crée s'il n'existe pas. |
UpdateItem | Écriture (UPDATE). Met à jour certains attributs (ex: "SET age = 31") sans écraser l'Item. (Utilise UpdateExpression). |
DeleteItem | Suppression (DELETE) d'un seul Item (par sa PK/SK). |
TransactWriteItems | (Avancé) Transaction "ACID" pour écrire (Put/Update/Delete) sur plusieurs Items (ou tables) en mode "tout ou rien". |
| Critère | Query (Requête) | Scan |
|---|---|---|
| Objectif | Lire un groupe d'Items (1-N). | Lire tous les Items. |
| Clé Requise | Oui (PK obligatoire). | Non. |
| Efficacité | Très Efficace (Saute à la partition). | Extrêmement Inefficace (Full Table Scan). |
| Coût (RCU) | Bas (Paye ce qui est lu). | Très Élevé (Paye pour toute la table). |
| Usage | 99% des cas (Production). (ex: WHERE UserID = 'A'). | (Maintenance, Export). À éviter en production. |
| Filtre | KeyConditionExpression (sur PK/SK).FilterExpression (sur autres attributs). | FilterExpression (sur autres attributs). |
Piège : FilterExpression (sur Query ou Scan) est appliqué APRÈS la lecture. Si vous faites un Scan + Filter (sur 1To), vous payez 1To de RCU, même si le filtre ne retourne qu'1 Item.
AWS CLI (aws dynamodb ...)
# Put (Écrire) un Item
$ aws dynamodb put-item \
--table-name Users \
--item '{
"UserID": {"S": "user-100"},
"Email": {"S": "alice@example.com"}
}'
# Get (Lire) un Item
$ aws dynamodb get-item \
--table-name Users \
--key '{"UserID": {"S": "user-100"}}'
# Query (Requête) (PK+SK)
$ aws dynamodb query \
--table-name Orders \
--key-condition-expression "UserID = :uid" \
--expression-attribute-values '{":uid": {"S": "User_A"}}'
# Scan (À ÉVITER)
$ aws dynamodb scan --table-name Users \
--filter-expression "Ville = :v" \
--expression-attribute-values '{":v": {"S": "Paris"}}'
Boto3 (Python SDK)
import boto3
# (Niveau Bas - Client) (Verbose)
client = boto3.client('dynamodb')
response = client.put_item(
TableName='Users',
Item={
'UserID': {'S': 'user-100'},
'Email': {'S': 'alice@example.com'}
}
)
# (Niveau Haut - Ressource) (Simple)
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')
# Put (Écriture)
table.put_item(
Item={
'UserID': 'user-100',
'Email': 'alice@example.com'
}
)
# Get (Lecture)
response = table.get_item(
Key={'UserID': 'user-100'}
)
item = response['Item']
# Query (Requête)
from boto3.dynamodb.conditions import Key
response = table.query(
KeyConditionExpression=Key('UserID').eq('User_A')
)DAX est un cache In-Memory (en mémoire vive), entièrement managé, "write-through", pour DynamoDB.
Le Problème
DynamoDB est rapide (millisecondes), mais pour des applications à très haute performance (Ad-Tech, Jeux), c'est encore trop lent. De plus, les lectures (RCU) coûtent cher à haute vélocité.
La Solution (DAX)
DAX est un cluster de cache (compatible API DynamoDB) que l'on place devant DynamoDB (dans le VPC).
Votre application (SDK) ne parle plus à DynamoDB, elle parle à l'Endpoint DAX.
Flux (Cache Hit) :
[App] -> (GetItem) -> [DAX Cluster]
[App] <- (Réponse Microseconde) <- [DAX Cluster]
Flux (Cache Miss) :
[App] -> (GetItem) -> [DAX Cluster]
│ (Cache Miss)
▼
[DynamoDB]
│ (Réponse ms)
▼
[App] <- (Réponse ms) <- [DAX Cluster] (Met en cache)Avantage : Latence de microseconde pour les lectures. Réduit drastiquement les coûts de RCU.
Inconvénient : Ne cache que GetItem, Query, Scan (Pas Put/Update). Coût (Cluster DAX à payer).
DynamoDB Streams est un flux (stream) ordonné de toutes les modifications (Inserts, Updates, Deletes) apportées aux Items d'une table. C'est du CDC (Change Data Capture).
Fonctionnement
- Vous activez "Streams" (ex: Type
NEW_AND_OLD_IMAGES) sur votre table. - (10:01) Vous écrivez
PutItem(UserID: "A", ... ). - (10:01) DynamoDB ajoute un "Record" au Stream (Log) :
{ Event: INSERT, NewImage: { ... } }. - (10:02) Vous faites
UpdateItem(UserID: "A", Age: 31). - (10:02) DynamoDB ajoute au Stream :
{ Event: MODIFY, OldImage: {Age: 30}, NewImage: {Age: 31} }.
Usage (Trigger Lambda)
L'usage n°1 est de connecter le Stream à une Fonction AWS Lambda.
Exemple : Un utilisateur change son nom (UpdateItem). Le Stream capture l'événement, déclenche une Lambda, qui va (par ex.) invalider le cache (Redis) ou envoyer l'update à un autre service (ex: Elasticsearch pour la recherche).
TTL (Time To Live) est une fonctionnalité (gratuite) qui permet à DynamoDB de supprimer automatiquement les Items expirés, sans consommer de WCU.
Fonctionnement
- Vous activez le TTL sur la table (ex: Attribut
expireAt). - Vous ajoutez un Attribut Timestamp (Epoch Unix, en secondes) à votre Item.
Item (Session Cache) :
{
"SessionID": "abc-123",
"data": "...",
// Timestamp Epoch (ex: dans 24 heures)
"expireAt": 1678886400
}DynamoDB (en arrière-plan) scanne et supprime (au mieux) les items dont expireAt est dans le passé.
Usage
- Gestion de Sessions (ex: cache de connexion).
- Stockage de Logs (ex: garder 30 jours de logs).
- Tâches (Queues) qui doivent expirer.
