Modèles de cohérence DAX et DynamoDB - Amazon DynamoDB

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Modèles de cohérence DAX et DynamoDB

Amazon DynamoDB Accelerator (Dax) est un service de mise en cache à écriture simultanée conçu pour simplifier l'ajout d'un cache à des tables DynamoDB. DAX opérant séparément de DynamoDB, il est important que vous compreniez les modèles de cohérence de DAX et de DynamoDB pour vous assurer que vos applications se comportent comme prévu.

Dans de nombreux cas d'utilisation, la façon dont une application utilise DAX a une incidence sur la cohérence des données au sein du cluster DAX, ainsi qu'entre DAX et DynamoDB.

Cohérence entre les nœuds d'un cluster DAX

Pour que votre application bénéficie d'une haute disponibilité, nous vous recommandons d'allouer au moins trois nœuds à votre cluster DAX. Puis, placez ces nœuds dans plusieurs zones de disponibilité d'une région.

Lorsqu'il s'exécute, votre cluster DAX réplique ainsi les données entre tous les nœuds du cluster (sous réserve que vous en ayez approvisionné plusieurs). Prenons l'exemple d'une application qui accomplit une opération UpdateItem à l'aide de DAX. Cette action entraîne la modification du cache d'éléments du nœud principal avec la nouvelle valeur. Cette valeur est ensuite répliquée sur tous les autres nœuds du cluster. Cette réplication est cohérente à terme et son exécution prend généralement moins d'une seconde.

Dans ce scénario, il est possible que deux clients lisent la même clé sur le même cluster DAX, mais reçoivent des valeurs différentes selon le nœud auquel chaque client accède. Les nœuds seront tous cohérents une fois que la mise à jour aura été entièrement répliquée sur tous les nœuds du cluster. (Ce comportement est similaire à celui de la cohérence éventuelle de DynamoDB.)

Si vous créez une application qui utilise DAX, cette application doit être conçue de façon à pouvoir tolérer des données éventuellement cohérentes.

Comportement du cache d'éléments DAX

Chaque cluster DAX est doté de deux caches : un cache d'éléments et un cache de requêtes. Pour plus d'informations, consultez Fonctionnement de DAX.

Cette section a trait aux implications en termes de cohérence de la lecture et de l'écriture dans le cache d'éléments DAX.

Cohérence des lectures

Avec DynamoDB, par défaut, l'opération GetItem effectue une lecture éventuellement cohérente. Supposons que vous utilisez UpdateItem avec le client DynamoDB. Si vous tentez de lire le même élément tout de suite après, les données se présenteront peut-être comme avant la mise à jour. Cela est dû au temps nécessaire à la propagation vers tous les emplacements de stockage DynamoDB. La cohérence est généralement atteinte en quelques secondes. Si vous tentez à nouveau de lire, il est probable que vous verrez l'élément mis à jour.

Lorsque vous utilisez GetItem avec le client DAX, l'opération (dans ce cas, une lecture éventuellement cohérente) se déroule comme suit.


                    Diagramme des flux de travail affichant les étapes numérotées de mise à jour d'un élément.
  1. Le client DAX émet une demande GetItem. DAX essaie de lire l'élément demandé dans le cache d'éléments. Si l'élément se trouve dans le cache (accès au cache), DAX le renvoie à l'application.

  2. Si l'élément n'est pas disponible (échec d'accès au cache), DAX effectue une opération GetItem éventuellement cohérente par rapport à DynamoDB.

  3. DynamoDB renvoie l'élément demandé que DAX stocke dans le cache d'éléments.

  4. DAX renvoie l'élément à l'application.

  5. (Non illustré) Si le cluster DAX contient plusieurs nœuds, l'élément est répliqué sur tous les autres nœuds du cluster.

L'élément reste dans le cache d'éléments DAX, conformément au paramètre de time-to-live (TTL) et à l'algorithme LRU (moins récemment utilisé) définis pour le cache. Pour plus d'informations, consultez Fonctionnement de DAX.

Toutefois, au cours de cette période, DAX ne relit pas l'élément à partir de DynamoDB. Si quelqu'un d'autre met à jour l'élément à l'aide d'un client DynamoDB, en ignorant totalement DAX, une demande GetItem effectuée à l'aide du client DAX génère des résultats différents de ceux que génère la même demande GetItem effectuée à l'aide du client DynamoDB. Dans ce scénario, DAX et DynamoDB contiennent des valeurs incohérentes pour la même clé tant que le time-to-live (TTL) de l'élément DAX n'a pas expiré.

Si une application modifie les données dans une table DynamoDB sous-jacente sans passer par DAX, l'application doit anticiper et tolérer les incohérences de données susceptibles d'apparaître.

Note

Outre la demande GetItem, le client DAX prend en charge les demandes BatchGetItem. Les demandes BatchGetItem encapsulant essentiellement une ou plusieurs autres demandes GetItem, DAX traite chacune de celles-ci comme une seule et même opération GetItem.

Cohérence des écritures

DAX est un cache d'écriture simultanée qui simplifie le processus de maintien de la cohérence entre le cache d'éléments DAX et les tables DynamoDB sous-jacentes.

Le client PutItem prend en charge les mêmes opérations d'API d'écriture que DynamoDB (, UpdateItem, DeleteItem, BatchWriteItem et TransactWriteItems). Lorsque vous utilisez ces opérations avec le client DAX, les éléments sont modifiés tant dans DAX que dans DynamoDB. DAX met à jour les éléments dans son cache d'élément, quelle que soit la valeur de time-to-live (TTL) de ces éléments.

Par exemple, supposons que vous émettez une demande GetItem à partir du client DAX pour lire un élément de la table ProductCatalog. (La clé de partition est Id ; il n'y a pas de clé de tri.) Vous extrayez l'élément dont Id a la valeur 101. La valeur QuantityOnHand de cet élément est 42. DAX stocke l'élément dans son cache d'éléments avec une TTL spécifique. Pour cet exemple, supposons que la durée de vie soit 10 minutes. Trois minutes plus tard, une autre application utilise le client DAX pour mettre à jour le même élément. La valeur QuantityOnHand de ce dernier est désormais 41. En supposant que l'élément ne soit pas à nouveau mis à jour, les lectures de ce même élément qui se produisent au cours des dix minutes qui suivent retournent la valeur mise en cache deQuantityOnHand (soit 41).

Comment DAX traite les écritures

DAX est destiné aux applications qui requièrent des lectures hautement performantes. En tant que cache d'écriture simultanée, DAX transmet vos écritures à DynamoDB de manière synchrone, puis réplique automatiquement et de manière asynchrone les mises à jour qui en résultent vers votre cache d'éléments dans tous les nœuds du cluster. Vous n'avez pas besoin de gérer une logique d'invalidation du cache, car DAX le fait à votre place.

DAX prend en charge les opérations d'écriture suivantes : PutItem, UpdateItem, DeleteItem, BatchWriteItem et TransactWriteItems.

Lorsque vous envoyez une demande PutItem, UpdateItem, DeleteItem ou BatchWriteItem à DAX, voici ce qui se produit :

  • DAX envoie la demande à DynamoDB.

  • DynamoDB répond à DAX, confirmant que l'écriture a abouti.

  • DAX écrit l'élément dans son cache d'éléments.

  • DAX indique au demandeur que l'opération a réussi.

Lorsque vous envoyez une demande TransactWriteItems à DAX, voici ce qui se produit :

  • DAX envoie la demande à DynamoDB.

  • DynamoDB répond à DAX, confirmant que la transaction est terminée.

  • DAX indique au demandeur que l'opération a réussi.

  • En arrière-plan, DAX effectue une demande TransactGetItems pour chaque élément dans la demande TransactWriteItems, afin de le stocker dans le cache d'éléments. TransactGetItems est utilisé pour assurer l'isolation sérialisable.

En cas d'échec de l'écriture sur DynamoDB pour une raison quelconque, y compris une limitation, l'élément n'est pas mis en cache dans DAX : L'exception relative à la défaillance est retournée au demandeur. Cela garantit que les données ne sont écrites dans le cache DAX que si elles ont préalablement écrites avec succès dans DynamoDB.

Note

Chaque écriture sur DAX modifie l'état du cache d'éléments. Cependant, les écritures sur le cache d'élément ne modifie pas le cache de requête. (Le cache d'éléments et le cache de requêtes DAX ayant des fonctions différentes, ils sont indépendants l'un de l'autre.)

Comportement du cache de requêtes DAX

DAX met en cache les résultats des demandes Query et Scan dans son cache de requêtes. Cependant, ces résultats n'affectent pas du tout le cache d'élément. Lorsque votre application émet une demande Query ou Scan avec DAX, l'ensemble de résultats est enregistré dans le cache de requêtes, non dans le cache d'éléments. Vous ne pouvez pas solliciter le cache d'élément en effectuant une opération Scan, car le cache d'élément et le cache de requête sont des entités distinctes.

Cohérence des opérations query-update-query

Les mises à jour du cache d'éléments ou de la table DynamoDB sous-jacente n'ont pas pour effet d'invalider ou de modifier les résultats stockés dans le cache de requêtes.

Pour bien comprendre cette distinction, prenez en compte le scénario suivant. Une application utilise la table DocumentRevisions, qui a DocId comme clé de partition et RevisionNumber comme clé de tri.

  1. Un client émet une demande Query pour DocId 101, pour tous les éléments dont le RevisionNumber est supérieur ou égal à 5. DAX stocke l'ensemble de résultats dans le cache de requêtes et le renvoie à l'utilisateur.

  2. Le client émet une demande PutItem pour DocId 101 avec RevisionNumber ayant la valeur 20.

  3. Le client émet la même opération Query que celle décrite à l'étape 1 (DocId 101 et RevisionNumber >= 5).

Dans ce scénario, le jeu de résultats mis en cache pour l'opération Query émise à l'étape 3 est identique à celui qui a été mis en cache à l'étape 1. Cela est dû au fait que DAX n'invalide pas les ensembles de résultats des demandes Query ou Scan en fonction de mises d'éléments individuels. L'opération PutItem de l'étape 2 n'apparaît dans le cache de requêtes DAX qu'à l'expiration du time-to-live (TTL) de la demande Query.

Votre application doit prendre en compte la valeur de durée de vie (TTL) du cache de requête, ainsi que le temps durant lequel votre application peut tolérer une incohérence de résultats entre le cache de requête et le cache d'élément.

Lectures transactionnelles à cohérence forte

Pour effectuer une demande GetItem, BatchGetItem, Query ou Scan fortement cohérence, vous devez définir le paramètre ConsistentRead sur true. DAX transmet des demandes de lecture fortement cohérentes à DynamoDB. Sitôt la réponse de DynamoDB reçue, DAX renvoie les résultats au client sans toutefois les mettre en cache. DAX ne peut pas assurer les lectures fortement cohérentes, car il n'est pas étroitement couplé à DynamoDB. C'est pourquoi, toute lecture subséquente à partir de DAX doit être une lecture éventuellement cohérente. Et toute lecture fortement cohérente subséquente doit être transmise à DynamoDB.

DAX gère les demandes TransactGetItems de la même façon que les lectures fortement cohérentes. DAX transmet toutes les demandes TransactGetItems à DynamoDB. Sitôt la réponse de DynamoDB reçue, DAX renvoie les résultats au client, mais ne les mets pas en cache.

Mise en cache négative

DAX prend en charge les entrées de cache négatives, tant dans le cache d'éléments que dans le cache de requêtes. Une entrée de cache négative se produit lorsque DAX ne trouve pas les éléments demandés dans une table DynamoDB sous-jacente. Au lieu de générer une erreur, DAX met en cache un résultat vide et le renvoie à l'utilisateur.

Par exemple, supposons qu'une application envoie une demande GetItem à un cluster DAX et que le cache d'éléments DAX ne contient aucun élément correspondant. DAX est alors contraint à lire l'élément correspondant dans la table DynamoDB sous-jacente. Si l'élément n'existe pas dans DynamoDB, DAX stocke un élément vide dans son cache d'éléments avant de renvoyer celui-ci à l'application. Supposons maintenant que l'application envoie un autre demande GetItem pour le même élément. DAX trouve l'élément vide dans le cache d'éléments et le renvoie immédiatement à l'application. À aucun moment il ne consulte DynamoDB.

Il reste une entrée de cache négative dans le cache d'éléments DAX jusqu'à ce que la TTL de l'élément expire, que son LRU soit appelé ou que l'élément soit modifié à l'aide de demandes PutItem, UpdateItem ou DeleteItem.

Le cache de requêtes DAX gère les résultats de cache négatifs de la même façon. Si une application effectue une opération Query ou Scan et que le cache de requêtes DAX ne contient pas de résultat mis en cache, DAX envoie la demande à DynamoDB. S'il n'existe pas d'élément correspondant dans l'ensemble de résultats, DAX stocke un ensemble de résultats vide dans le cache de requêtes, puis le renvoie à l'application. Les demandes Query ou Scan ultérieures génèrent le même jeu de résultats (vide) tant que le jeu de résultats n'a pas expiré.

Politiques pour les écritures

Le comportement d'écriture simultanée de DAX est adapté pour un grand nombre de modèles d'application. Toutefois, le modèle d'écriture simultanée peut ne pas convenir à certains modèles d'application.

Pour les applications sensibles à la latence, l'écriture via DAX génère un tronçon de réseau supplémentaire. Par conséquent, une écriture dans DAX est un peu plus lente qu'une écriture directe dans DynamoDB. Si votre application est sensible à la latence d'écriture, vous pouvez réduire celle-ci en écrivant directement dans DynamoDB. Pour plus d'informations, consultez Écriture directe.

Pour les applications qui génèrent beaucoup d'écritures (comme celles qui procèdent à des chargements de données en bloc), il n'est peut-être pas souhaitable de passer par DAX pour écrire toutes les données, car l'application ne lit qu'un faible pourcentage de celles-ci. Lorsque vous écrivez de grandes quantités de données via DAX, celui-ci doit appeler son algorithme LRU afin de ménager de l'espace dans le cache pour les nouveaux éléments à lire. Cela a pour effet de diminuer l'efficacité de DAX en tant que cache de lecture.

Lorsque vous écrivez un élément dans DAX, l'état du cache d'éléments change pour accueillir le nouvel élément. (Par exemple, DAX peut être amené à expulser les données les plus anciennes du cache d'éléments afin de ménager de l'espace pour le nouvel élément.) Le nouvel élément reste dans le cache d'élément, selon l'algorithme LRU et le paramètre de durée de vie (TTL) du cache. Tant que l'élément reste dans le cache d'éléments, DAX ne le relit pas dans DynamoDB.

Écriture simultanée

Le cache d'éléments DAX implémente une politique d'écriture simultanée. Pour plus d'informations, consultez Comment DAX traite les écritures.

Lorsque vous écrivez un élément, DAX vérifie que l'élément mis en cache est synchronisé avec l'élément tel qu'il existe dans DynamoDB. Cela est utile pour les applications qui ont besoin de relire un élément de suite après l'avoir écrit. Toutefois, si d'autres applications écrivent directement dans une table DynamoDB, l'élément figurant dans le cache d'éléments DAX n'est plus synchronisé avec DynamoDB.

Pour illustrer cela, prenons l'exemple de deux utilisateurs (Alice et Bob) qui utilisent la tableProductCatalog. Alice accède à la table via DAX, mais Bob contourne DAX et accède à la table directement dans DynamoDB.


                    Diagramme de flux de travail illustrant les étapes numérotées de l'accès des utilisateurs Alice et Bob à une table à l'aide de DAX et DynamoDB.
  1. Alice met à jour un élément dans la table ProductCatalog. DAX transmet la demande à DynamoDB et la mise à jour aboutit. DAX écrit ensuite l'élément dans son cache d'éléments et renvoie une réponse positive à Alice. À partir de là, tant que l'élément n'est pas expulsé du cache, tout utilisateur qui lit l'élément à partir de DAX voit l'élément avec la mise à jour d'Alice.

  2. Quelques instants plus tard, Bob met à jour le même élément ProductCatalog qu'Alice a écrit. Cependant, Bob met à jour l'élément directement dans DynamoDB. DAX n'actualise pas automatiquement son cache d'éléments en réponse aux mises à jour via DynamoDB. Par conséquent, les utilisateurs de DAX ne voient pas la mise à jour de Bob.

  3. Alice lit à nouveau l'élément à partir de DAX. Sachant que l'élément se trouve dans le cache d'éléments, DAX le renvoie à Alice sans accéder à la table DynamoDB.

Dans ce scénario, Alice et Bob voient des représentations différentes du même élément ProductCatalog. Ce sera le cas tant que DAX n'aura pas expulsé l'élément du cache d'éléments ou qu'un autre utilisateur n'aura pas remis à jour ce même élément à partir de DAX.

Écriture directe

Si votre application a besoin d'écrire de grandes quantités de données (par exemple, pour charger des données en bloc), il peut être judicieux de contourner DAX et d'écrire les données directement dans DynamoDB. Une telle stratégie d'écriture non allouée réduit la latence d'écriture. Cependant, le cache d'éléments ne reste pas synchronisé avec les données dans DynamoDB.

Si vous décidez d'utiliser une politique d'écriture simultanée, ne perdez pas de vue que DAX remplit son cache d'éléments chaque fois que des applications utilisent le client DAX pour lire des données. Dans certains cas, vous pouvez en tirer des avantages, car seules les données les plus fréquemment lues sont mises à en cache (et non les données les plus fréquemment écrites).

Prenons, par exemple, le cas d'un utilisateur (Charlie) qui souhaite travailler avec une autre table, la table GameScores, en utilisant DAX. Sachant que la clé de partition de GameScores est UserId, tous les scores de Charlie ont le même UserId.


                    Diagramme de flux de travail illustrant les étapes numérotées de l'utilisation par Charlie d'une table DynamoDB avec DAX.
  1. Charlie souhaitant récupérer tous ses scores. Il envoie une demande Query à DAX. Présumant que cette requête n'a pas été émise auparavant, DAX l'achemine vers DynamoDB pour traitement. Il stocke les résultats dans le cache de requêtes DAX avant de les renvoyer à Charlie. Le jeu de résultats reste disponible dans le cache de requête jusqu'à ce qu'il soit expulsé.

  2. Supposons maintenant que Charlie joue au jeu Meteor Blasters et qu'il atteint un score élevé. Charlie envoie une demande UpdateItem à DynamoDB, modifiant ainsi un élément dans la table GameScores.

  3. Enfin, Charlie décide de réexécuter son opération Query précédente pour extraire toutes ses données de GameScores. Charlie ne trouve pas le score élevé qu'il a obtenu à Meteor Blasters dans les résultats. Cela est dû au fait que les résultats de la requête proviennent du cache de requête, et non du cache d'élément. Les deux caches étant indépendants l'un de l'autre, toute modification dans un cache ne se répercute pas dans l'autre cache.

DAX n'actualise pas les ensembles de résultats dans le cache de requêtes avec les données les plus récentes de DynamoDB. Chaque jeu de résultats du cache de requête correspond au moment où l'opération Query ou Scan a été effectuée. Par conséquent, les résultats de l'opération Query de Charlie ne reflètent pas son opération PutItem. C'est le cas jusqu'à ce que DAX expulse l'ensemble de résultats du cache de requêtes.