Le Blog Amazon Web Services
DynamoDB Streams : cas d’usages et design patterns
Cet article décrit les cas d’usages communs, ainsi que les options de design et les solutions, lors de la migration d’une base de données relationnelle vers Amazon DynamoDB.
Nous examinons comment gérer les scénarios suivants :
- Comment configurer une relation entre plusieurs tables dans lesquelles, en fonction de la valeur d’un élément d’une table, vous mettez à jour l’élément dans une deuxième table
- Comment déclencher un évènement basé sur la modification d’un élément particulier
- Comment auditer ou archiver les données
- Comment répliquer les données sur plusieurs tables (similaire à ce que permettent des vues matérialisées/flux de données/réplication dans des bases de données relationnelles)
Vous pouvez utiliser DynamoDB Streams pour adresser tous ces cas d’usage. DynamoDB Streams est un service que vous pouvez combiner avec d’autres services AWS pour résoudre de nombreux problèmes similaires. Lorsque vous activez DynamoDB Streams, il capture une séquence chronologique de modifications au niveau des objets d’une table DynamoDB et stocke les informations de manière durable jusqu’à 24 heures. Les applications peuvent accéder à un flux d’enregistrements contenant les changements d’éléments, à partir d’un flux DynamoDB, en temps quasi réel.
AWS gère des points d’accès distincts DynamoDB Streams et DynamoDB. Pour accéder aux tables et aux indexes de la base de données, votre application doit accéder à un point d’accès DynamoDB. Pour lire et traiter des enregistrements DynamoDB Streams, votre application doit accéder à un point d’accès DynamoDB Streams dans la même région.
DynamoDB Streams supporte les vues des flux d’enregistrements suivants :
KEYS_ONLY
—Uniquement les attributs clés de l’élément modifiéNEW_IMAGE
—L’image de l’élément modifié, après modificationOLD_IMAGE
—L’image de l’élément modifié, avant modificationNEW_AND_OLD_IMAGES
—A la fois l’ancienne et la nouvelle image de l’élément modifié
Vous pouvez traiter les flux DynamoDB Streams de plusieurs façons. La façon la plus commune consiste à utiliser AWS Lambda, ou bien une application autonome utilisant Kinesis Client Library (KCL) avec l’adaptateur DynamoDB Streams Kinesis. KCL est une bibliothèque client fournissant une interface de traitement des flux de modifications DynamoDB Streams. l’adaptateur DynamoDB Streams Kinesis traite ce flux afin d’avoir une vue sur les enregistrements uniques retournés par DynamoDB Streams. Lambda exécute votre code basé sur un évènement de DynamoDB Streams (insertion/mise à jour/suppression d’un élément). Dans cette approche, le service AWS Lambda scrute le flux DynamoDB Streams et, dès qu’il détecte une modification, appelle la fonction Lambda en lui passant un ou plusieurs éléments en paramètre.
Design patterns DynamoDB Streams
Le schéma suivant décrit une architecture de référence pour différents cas d’usages reposant sur DynamoDB Streams et d’autres services AWS.
Considérons un cas d’usage simple de stockage et de consultation de transactions de factures depuis une table DynamoDB nommée InvoiceTransactions.
Une seule facture peut contenir plusieurs milliers de transactions par client. La clé de partition est InvoiceNumber
, et la clé de tri est TransactionIdentifier
afin de supporter l’unicité et de fournir des capacités d’interrogation en utilisant la clé InvoiceNumber
. Le schéma suivant montre le design de la table.
Nom de la table : InvoiceTransactions
Partition Key | Sort Key | Attribute1 | Attribute2 | Attribute3 | Attribute4 |
InvoiceNumber | TransactionIdentifier | Amount | Trans_country | Invoice_dt | InvoiceDoc |
1212121 | Client1_trans1xxxx | $100 | USA | 6062016 | {JSON Doc1} |
1212121 | Client1_trans2xxxx | $500 | USA | 6062016 | {JSON Doc2} |
1212122 | Client2_trans1xxx | $200 | UK | 6062016 | {JSON Doc3} |
1212121 | Client2_trans1xxxx | $500 | China | 6062016 | {JSON Doc4} |
Maintenant, supposons qu’on insère un nouvel élément
1212123 | Client3_trans1xxx | $1,000 | USA |
Après cette insertion, le flux DynamoDB Streams possède l’entrée suivante.
Type de vue | Valeurs |
New image | TransactionIdentifier= Client3_trans1xxx,InvoiceNumber=1212123,Amount-$1000,Trans_country=USA |
Keys only | InvoiceNumber=1212123, TransactionIdentifier= Client3_trans1xxx |
Maintenant, supposons que, vu la nature de ce cas d’usage, l’application demande des capacités d’audit, de recherche, d’archivage, de notification et d’agrégation à chaque modification dans la table InvoiceTransactions
. Examinons comment vous pourriez utiliser le flux de données pour couvrir différents cas d’usages.
Implémentation de capacités transactionnelles avec plusieurs tables
DynamoDB supporte les transactions, pour implémenter une logique métier qui nécessite plusieurs opérations “tout ou rien” sur les éléments d’une ou de plusieurs tables. Vous pouvez utiliser les APIs de transaction côté serveur de DynamoDB pour adresser ces cas d’usages, avec un modèle de consistance forte.
Cependant, si votre besoin est d’utiliser DynamoDB comme une vue matérialisée sur des données stockées sur une ou plusieurs tables, pour une recherche rapide ou une validation, vous pouvez utiliser les données du flux pour ce faire. Ces vues matérialisées possèdent généralement des patterns d’accès et des caractéristiques différentes. Il faut garder à l’esprit que vous pouvez appliquer des modifications d’une façon éventuellement consistante. Voici quelques exemples :
- Agrégation : Considérons un scenario dans lequel vous avez besoin de maintenir le montant total en dollars pour chaque facture, pour des besoins de reporting. Ce total devrait être mis à jour dynamiquement quand des nouveaux éléments sont insérés dans la table
InvoiceTransactions
ou d’autres tables en relation, et maintenu à jour. Pour calculer le total, créer une nouvelle table avec la structure suivante :
Nom de la table : InvoiceTotal
Clé de partition | Attribut numérique | Attribut chaîne de caractères |
InvoiceNumber | Total | Update_date |
1212121 | $1,100 | 6062016 |
1212122 | $200 | 6072016 |
A chaque modification dans la table InvoiceTransactions
, vous mettez à jour le total. Essayons de faire ceci en utilisant une expression de mise à jour comme ceci:
La valeur :Amount
peut être lue depuis le flux de modifications DynamoDB à chaque fois qu’un élément est ajouté à la table InvoiceTransactions
, et :date
peut être la date en cours. L’opérateur ADD
est la commande. Pour un attribut numérique, il additionne la valeur spécifiée à l’attribut. SET
est un autre opérateur de commande. Il indique que les attributs suivants vont être mis à jour.
- Agrégation conditionnelle : Considérons un scenario dans le quel vous avez besoin d’enregistrer le nombre de transactions par pays pour les factures qui sont affectées à un responsable pour vérification. Dans ce cas, vous créez une nouvelle table
InvoiceAction
avec la structure suivante:
Nom de la table : InvoiceAction
InvoiceNumber (Clé de partition) | Trans_country (clé de tri) | Verify_action | Total_trans |
1212121 | USA | admin@com | 2 |
1212121 | UK | admin@co.uk | 1 |
1212121 | China |
A chaque modification dans la table InvoiceTransactions
, vous mettez à jour le total en utilisant une expression de mise à jour avec une écriture conditionnelle comme ceci:
Cette opération échoue avec une erreur ConditionalCheckFailedException
pour les pays dans lesquels il n’y a pas de responsable affecté — par exemple, la Chine dans ce scenario.
- Réplication : Dans les bases de données relationnelles, il existe des outils qui sont généralement utilisés pour répliquer les données depuis une table maitre vers des tables filles, pour des besoins de requêtage (déchargement des requêtes/réplication des données). De la même manière, en utilisant DynamoDB Streams, vous pouvez répliquer la table
InvoiceTransactions
vers des régions différentes pour des besoins de faible latence ou de reporting. Vous pouvez utiliser DynamoDB global tables pour répliquer les données vers d’autres régions AWS. Les tables globales utilisent DynamoDB Streams afin de propager les modifications entre les replicas dans les différentes régions AWS.
Archivage/audit
Cas d’usage : Supposons que l’on ait un besoin métier de stocker toutes les transactions des factures pour une durée allant jusqu’à 7 ans, pour des besoins de conformité ou d’audit. Les utilisateurs ont également besoin de lancer des requêtes ad-hoc sur ces données.
Solution : DynamoDB est idéal pour stocker les données (chaudes) temps réel qui sont accédées fréquemment. Après un certain temps, dépendant du cas d’usage, les données ne sont plus “chaudes”, et sont typiquement archivées dans un système de stockage comme Amazon S3. Vous pouvez concevoir une solution utilisant Amazon Kinesis Data Streams, Amazon Kinesis Data Firehose, et Amazon S3. Kinesis Data Firehose est un service entièrement géré que vous pouvez utiliser pour charger le flux de données dans Amazon S3, Amazon Redshift, ou Amazon OpenSearch Service, en utilisant des appels d’API. Il peut également lotir, compresser, transformer et chiffrer les données avant de les charger, ce qui permet d’économiser l’espace de stockage utilisé et de renforcer la sécurité
Ce qui suit est une description de haut niveau de la solution.
- Créer un nouveau flux de données dans Kinesis Data Streams (par exemple, ddbarchive).
- Activer le streaming vers Kinesis sur une table DynamoDB en utilisant la console ou l’API. A chaque création, modification, ou suppression d’un élément dans la table
InvoiceTransactions
, DynamoDB enverra un enregistrement vers Kinesis. - Créer un flux de livraison Kinesis Data Firehose pour traiter les enregistrements depuis ddbarchive, et les stocker dans une destination comme Amazon S3, pour persister les données du flux DynamoDB. Par défaut, Kinesis Data Firehose ajoute un préfixe de temps UTC au format
YYYY/MM/DD/HH
avant d’écrire les fichiers sur S3. Vous pouvez modifier cette structure de répertoire en ajoutant votre répertoire de premier niveau (par exemple,Invoice/YYYY/MM/DD/HH
pour stocker les transactions de facture). - Kinesis Data Firehose lotit les données et les stocke dans Amazon S3 en se basant soit sur une taille tampon (1-128 Mo), soit sur une intervalle tampon (60-900 seconds). Le premier critère rempli déclenche l’envoi des données vers Amazon S3.
- Mettre en place des règles de cycle de vie S3 pour déplacer les données vers la classe de stockage S3-IA (accès moins fréquent) ou Amazon Glacier afin de réduire les coûts.
- Vous pouvez également utiliser DynamoDB Time to Live (TTL), qui simplifie l’archivage en supprimant automatiquement des éléments basés sur un attribut horodaté. Par exemple, vous pouvez désigner
Invoice_dt
comme étant un attribut TTL en stockant sa valeur au format epoch. Pour un exemple d’implémentation, vous pouvez lire l’article (en anglais) Automatically Archive Items to S3 Using DynamoDB TTL with AWS Lambda and Amazon Kinesis Firehose. - Une option alternative consiste à utiliser les fonctionnalités natives de DynamoDB pour exporter vers S3 (article en anglais), sans devoir écrire du code. Une fois vos données stockées dans votre bucket S3, vous pouvez utiliser Amazon Athena pour lancer des requêtes ad hoc sur les données, à des fins d’audit et de conformité.
Reporting
Cas d’usage : Comment lancer des requêtes rapides en temps réel sur DynamoDB ?
Solution : Concevoir le schéma des tables DynamoDB basé sur les besoins du reporting et ses patterns d’accès. Par exemple, si vous avez besoin d’un reporting en temps réel sur les transactions de facture, vous pouvez accéder aux données de factures ou transactions directement en utilisant les appels d’API Query
ou GetItem
. Concevez votre schéma avec une clé de partition (ou la combinaison d’une clé de partition et d’une clé de tri) adapté aux besoins des requêtes. De plus, vous pouvez créer des indexes locaux secondaires et des indexes globaux secondaires pour supporter l’accès à la table via d’autres attributs.
Exemple : les requêtes suivantes peuvent être utilisées sur des tableaux de bord temps-réel. Dans cet exemple, la table invoiceTotal
possède les attributs total
, update_date
, etc., et est partitionnée par invoice_number
. La table invoiceTransactions
possède les attributs InvoiceNumber
et TransactionIdentifier
. Elle est partitionnée sur ces deux attributs, en utilisant InvoiceNumber
comme clé de partition et Transaction_Identifier
comme clé de tri (clé primaire composite). Vous avez les besoins suivants pour votre reporting en temps réel :
- Lister toutes les transactions pour un
InvoiceNumber
donné. Solution : Appeler l’APIQuery
en utilisantInvoiceNumber
comme clé de partition, sans utiliser la clé de tri. - Lister toutes les transactions pour un
InvoiceNumber
tel que l’attributTransactionIdentifier
commence parclient1_.xxx
. Solution : Appeler l’APIQuery
en utilisantInvoiceNumber
comme clé de partition, et une expression de condition sur la cléTransactionIdentifier
. - Lister le total par
InvoiceNumber
. Solution : Appeler l’APIGetItem
avec la cléInvoiceNumber.
Cas d’usage : Comment exécuter des requêtes analytiques sur des données stockées dans DynamoDB ?
Solution : Pour les cas d’usage peu fréquents, vous pouvez utiliser Amazon Athena Federated Query ou Amazon EMR avec HiveQL pour exécuter des requêtes directement sur DynamoDB. DynamoDB est optimisé pour les transactions en ligne, où la majorité des opérations sur les données sont indexées (et matérialisées – pour éviter des variations des performances). Pour les cas d’analyses fréquentes, il est généralement préférable d’exporter les données DynamoDB (périodiquement ou par réplication en continu basée sur un flux) vers un entrepôt de données comme Amazon Redshift, qui est optimisé, par son format de stockage, pour exécuter de façon plus efficace des agrégations de données.
Voici un résumé de cette solution :
- Amazon Redshift est un entrepôt de données géré, qui supporte nativement l’exécution de requêtes analytiques complexes.
- Activer le streaming sur la table DynamoDB, ce qui active la capture d’évènements en temps quasi réel dans un flux de données Kinesis. Créer le flux de livraison Firehose pour consommer le flux de données, en configurant Amazon Redshift comme destination.
- Kinesis Data Firehose utilise un bucket S3 intermédiaire, et la commande
COPY
pour charger les données dans Amazon Redshift. - Utiliser Amazon QuickSight ou un outil standard de BI (Business Intelligence) pour lancer des requêtes sur Amazon Redshift.
- Pour plus d’informations sur l’implémentation d’un pipeline de données utilisant Kinesis Firehose, Amazon Redshift, et Amazon QuickSight, se référer à l’article (en anglais) Amazon Kinesis – Setting up a Streaming Data Pipeline.
Option alternative : utiliser la commande COPY d’Amazon Redshift pour lire la table DynamoDB et la charger dans Amazon Redshift. Référez vous à la documentation DynamoDB pour plus de détails.
Exemple : Les requêtes similaires à celles-ci sont mieux exécutées sur Amazon Redshift.
- Obtenir le montant journalier depuis la table
invoiceTransactions
sur les trois dernières années. - Sélectionner
max(invoice_amount)
,sum(total_amount)
, etcount(invoice_trans)
depuis la tableInvoice Transactions group_by YYYYHHMMDD
.
Notifications/messages
Cas d’usage : Supposons un scénario avec la table InvoiceTransactions
, où à chaque fois qu’une valeur zéro est insérée ou mise à jour dans l’attribut amount
, l’équipe concernée doit immédiatement être notifiée pour action.
Solution : Construire une solution utilisant DynamoDB Streams, Lambda et Amazon SNS pour traiter ce scénario.
Voici un résumé de la solution :
- Définir une rubrique SNS et des abonnements (e-mail ou SMS).
- Utiliser Lambda pour lire le flux DynamoDB et vérifier si le montant de la facture est de zéro. Puis, publier un message vers la rubrique SNS. Par exemple : “Merci de prendre une action sur la facture 1212121 ayant un montant à zéro dans la table
InvoiceTransactions
à YYMMHH24MISS” - Les abonnés reçoivent des notifications en quasi temps réel et peuvent entreprendre les actions appropriées.
Pour plus d’informations sur l’implémentation de cette solution, référez vous à l’article (en anglais) Building NoSQL Database Triggers with Amazon DynamoDB and AWS Lambda.
Cas d’usage : Supposons un scénario où à chaque saisie d’une nouvelle facture, les données doivent être envoyées à un système en aval d’exécution des paiements.
Solution : Vous pouvez construire une solution utilisant DynamoDB Streams, Lambda, Amazon SNS, et Amazon SQS pour traiter ce type de scénarios. Supposons que le système aval de paiement attende un message SQS pour déclencher un processus de paiement.
Voici un résumé de la solution :
- Définir une rubrique Amazon SNS avec Amazon SQS comme abonné. pour plus de détails, référez vous à la Documentation d’Amazon SNS.
- Utiliser une fonction Lambda pour lire le flux DynamoDB et vérifier s’il y a une nouvelle transaction de facturation, puis envoyer un message SNS.
- Le message SNS est délivré à la file SQS.
- Dès que le message arrive, le système en aval peut interroger la file SQS et déclencher le traitement.
Recherche
Cas d’usage : Comment réaliser des recherche par texte libre, sur DynamoDB ? Par exemple, supposons que la table InvoiceTransactions
contient un attribut InvoiceDoc
de type document, contenant un document JSON tel que décrit dans le tableau si-dessous. Comment filtrer sur une transaction client en particulier, ou bien interroger des données (quantité de “printers”/“desktops”, noms de fournisseurs contenant %1%, etc.) dans l’attribut de type document sur DynamoDB?
Clé de partition | Clé de tri | Attribute4 |
InvoiceNumber | TransactionIdentifier | InvoiceDoc |
1212121 | Client1_trans1xxxx |
Partition Key Sort Key Attribute4 InvoiceNumber TransactionIdentifier InvoiceDoc 1212121 Client1_trans1xxxx { “Vendor Name”: “Vendor1 Inc”, “NumberofItems”: “5”, “ItemsDesc”: [ { “laptops”: { “Quantity”: 2 }, “desktops”: { “Quantity”: 1 }, “printer”: { “Quantity”: 2 } } ] } |
Solution : DynamoDB n’est pas adapté pour de la recherche par texte libre sur des larges volumes de données. nous recommandons d’utiliser Amazon OpenSearch Service pour adresser ce type de besoins.
Voici un résumé de la solution :
- Dans ce design, la table DynamoDB
InvoiceTransactions
est utilisé comme entrepôt primaire. un cluster Amazon OpenSearch est utilisé pour fournir tous les types de recherche en indexant la tableInvoiceTransactions
table. - En utilisant DynamoDB streams, toute création, mise à jour ou suppression d’un élément dans la table est capturé puis traité par une fonction Lambda. Cette dernière effectue les appels nécessaires à Amazon OpenSearch pour indexer les données en temps quasi réel.
- Pour plus d’informations sur cette architecture, référez vous à l’article (en anglais) Indexing Amazon DynamoDB Content with Amazon Elasticsearch Service Using AWS Lambda ou bien Loading Streaming Data into Amazon ES from Amazon DynamoDB
- Comme alternative, vous pouvez utiliser la fonctionnalité de streaming pour envoyer les modification vers Amazon OpenSearch via un flux de livraison Firehose. Avant de charger les données dans Amazon OpenSearch, vous pourriez avoir besoin d’effectuer des transformations sur ces données. Vous pouvez utiliser des fonctions Lambda pour ceci; pour plus d’informations, se référer à Data Transformation.
OpenSearch supporte également tous les types de recherche par texte libre, incluant le tri et l’agrégation des résultats. La flexibilité est un autre avantage de cette approche. OpenSearch Query peut être facilement modifié pour ajouter de nouveaux filtres, et Amazon OpenSearch fournit nativement cette possibilité. Par exemple, si vous ajoutez un nouvel attribut dans la table DynamoDB, il sera automatiquement disponible pour des requêtes sur Amazon OpenSearch.
Meilleures pratiques en utilisant DynamoDB Streams
Gardez à l’esprit ces meilleures pratiques lorsque vous concevez des solutions utilisant DynamoDB Streams :
- DynamoDB Streams vous permet de construire des solutions utilisant une synchronisation des données en quasi temps réel. Elle n’assure pas une consistance ou une gestion des transactions sur plusieurs tables. Ceci doit être géré au niveau de l’application. Il faut également être conscient de la latence (inférieure à une seconde) dans le traitement du flux de données. Ceci vous permet de définir le SLA concernant la disponibilité des données dans vos applications en aval et auprès des utilisateurs finaux.
- Toutes les modifications d’un élément seront dans le flux, y compris les suppressions. Votre application doit être capable de traiter les suppressions, mises à jour et créations.
- Concevez votre composant de traitement du flux pour traiter tous les types d’exceptions. Assurez vous de stocker vos données de flux dans une “dead letter queue” (DLQ) comme SQS ou S3, pour un traitement différé des échecs.
- Les échecs peuvent se produire dans l’application qui lit l’évènement depuis le flux. Vous pouvez concevoir l’application de façon à minimiser le risque et l’étendue de l’erreur/incident. Pour cela, essayez de ne pas mettre à jour plusieurs tables au sein du même code. De plus, vous pouvez concevoir vos tables de façon à mettre à jour plusieurs attributs d’un même élément (plutôt que cinq attributs différents, par exemple). Vous pouvez également concevoir votre traitement de façon à ce qu’il soit idempotent, ce qui vous permet de rejouer le traitement en cas d’erreur. Vous devriez également capturer les différentes exceptions dans votre code et décider si vous souhaitez les rejouer les enregistrements ou bien les ignorer et les enregistrer dans la DLQ pour une analyse ultérieure
- Vous devez être conscients des contraintes suivantes lorsque vous concevez des applications consommatrices:
- La rétentions des données du flux DynamoDB Streams est de 24 heures
- Au plus deux processus peuvent lire depuis le flux simultanément.
- On vous recommande de considérer Lambda pour traiter le flux quand cela est possible, car Lambda est serverless et donc plus simple à gérer. Évaluez d’abord si Lambda peut être utilisé, et si ce n’est pas le cas, vous pouvez utiliser la librairie client Kinesis (Kinesis Client Library – KCL). La table de comparaison suivante vous permet de décider:
Paramètre | AWS Lambda | Kinesis Client Library |
Déploiement | Lambda scrute le flux DynamoDB stream et appelle votre fonction/code dès qu’un nouvel enregistrement est détecté. | Vous écrivez votre propre application utilisant KCL avec DynamoDB Streams Kinesis Adapter, et l’hébergez sur une instance EC2. |
Facilité de gestion | Lambda scale automatiquement en fonction de la charge | Vous devez utiliser les shards, la surveillance, la mise à l’échelle, et des points de contrôle en phase avec les meilleures pratiques KCL. (Pour plus d’informations, voir cet article (en anglais) sur la conception et cet article (en anglais) sur la surveillance.) |
Comment cela fonctionne | Pour chaque partition DynamoDB, il y a un shard correspondant, et une fonction Lambda scrute les évènements dans le flux (shard). En fonction de la taille de batch que vous spécifiez, la fonction extrait les enregistrements, les traite, puis passe au batch suivant. | – Enumère les shards dans le flux – Coordonne l’association des shards avec d’autres processus (s’il y en a) – Instancie un processeur d’enregistrement pour chaque shard à traiter – Récupère les enregistrements depuis le flux – Envoie les enregistrements au processeur d’enregistrements correspondant – Effectues les vérifications de point de contrôle des enregistrements traités |
Temps d’exécution | Le temps d’exécution maximum par requête est de 900 secondes | Il n’y a pas de restriction |
Disponibilité | Lambda est un service géré par AWS et hautement disponible. Il n’y a pas de fenêtre de maintenance ou de temps d’arrêts programmés. | L’application doit être hébergée au sein d’un groupe d’Autoscaling EC2 pour la haute disponibilité |
Autres considérations | Notez l’impact des limites des payloads Lambda en utilisant Lambda pour consommer des flux. Toute donnée de type _IMAGE peut la dépasser, en particulier pour les attributs larges. Vous devez donc spécifier une taille de lot en prenant cela en compte. |
Récapitulatif
DynamoDB Streams est un service que vous pouvez combiner avec d’autres services AWS afin de créer des solutions pratiques pour migrer depuis des bases de données relationnelles vers DynamoDB. Cet article décrit quelques cas d’usage communs et les solutions à retenir, avec les bonnes pratiques que vous devriez respecter en utilisant DynamoDB Streams.
Article initialement publié par Gowri Balasubramanian Solutions Architect, et adapté en français par Moncef Atouf, Solutions Architect dans les équipes AWS France.