Modelos de consistencia de DAX y DynamoDB - Amazon DynamoDB

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Modelos de consistencia de DAX y DynamoDB

Amazon DynamoDB Accelerator (DAX) es un servicio de almacenamiento en caché de escritura indirecta (write-through), diseñado para simplificar el proceso de agregar una caché a las tablas de DynamoDB. Dado que DAX funciona por separado de DynamoDB, es importante comprender los modelos de consistencia de DAX y de DynamoDB para asegurarse de que sus aplicaciones se comporten como se espera de ellas.

En muchos casos de uso, la forma de usar DAX en la aplicación afecta a la consistencia de datos en el clúster de DAX, así como a la consistencia de datos entre DAX y DynamoDB.

Consistencia entre los nodos de los clústeres de DAX

Para dotar de alta disponibilidad a la aplicación, recomendamos aprovisionar el clúster de DAX con al menos tres nodos. A continuación, coloque los nodos en varias zonas de disponibilidad de una región.

Mientras el clúster de DAX se está ejecutando, replica los datos entre todos los nodos del clúster (siempre y cuando haya aprovisionado más de uno). Tomemos una aplicación que realiza correctamente una operación UpdateItem mediante DAX. Esta acción hace que la caché de elementos del nodo principal se modifique con el nuevo valor. A continuación, este valor se replica en todos los demás nodos del clúster. Esta replicación presenta consistencia final y suele tardar menos de un segundo en llevarse a cabo.

En esta situación, es posible que dos clientes lean la misma clave del mismo clúster de DAX pero reciban valores distintos, según a qué nodo haya obtenido acceso cada cliente. Todos los nodos serán consistentes cuando la actualización haya terminado de replicarse en todos los nodos del clúster. (Este comportamiento se asemeja a la naturaleza consistente final de DynamoDB).

Si va a crear una aplicación que utiliza DAX, dicha aplicación debe diseñarse de forma que tolere los datos de consistencia final.

Comportamiento de la caché de elementos de DAX

Cada clúster de DAX tiene dos memorias caché diferentes —una caché de elementos y una caché de consultas. Para obtener más información, consulte DAX: cómo funciona.

En esta sección se abordan las implicaciones para la consistencia de las lecturas y escrituras en la caché de elementos de DAX.

Consistencia de lectura

De forma predeterminada, con DynamoDB la operación GetItem lleva a cabo una lectura consistente final. Suponga que utiliza UpdateItem con el cliente de DynamoDB. Si inmediatamente después intenta leer el mismo elemento, es posible que los datos aparezcan igual que antes de la actualización. Esto se debe al retraso de propagación entre todas las ubicaciones de almacenamiento de DynamoDB. Normalmente, se logra la coherencia en cuestión de segundos. Si reintenta la lectura, probablemente verá el elemento actualizado.

Cuando se utiliza GetItem con el cliente de DAX, la operación (en este caso, una lectura consistente final) se lleva a cabo como se muestra a continuación.


                    Diagrama de flujo de trabajo que muestra los pasos con números para actualizar un elemento.
  1. El cliente de DAX emite una solicitud GetItem. DAX intenta leer el elemento solicitado en la caché de elementos. Si el elemento está presente en la caché (acierto de caché), DAX se lo devuelve a la aplicación.

  2. Si el elemento no está disponible (error de caché), DAX realiza una operación GetItem de consistencia final en DynamoDB.

  3. DynamoDB devuelve el elemento solicitado y DAX lo almacena en la caché de elementos.

  4. DAX devuelve el elemento a la aplicación.

  5. (No se muestra) Si el clúster de DAX contiene más de un nodo, el elemento se replica en todos los demás nodos del clúster.

El nuevo elemento permanecerá en la caché de elementos de DAX, de conformidad con el algoritmo de elementos menos usados recientemente (LRU) y el Tiempo de vida (TTL) de la caché. Para obtener más información, consulte DAX: cómo funciona.

Sin embargo, durante este periodo, DAX no vuelve a leer el elemento en DynamoDB. Si otra persona actualiza el elemento mediante un cliente de DynamoDB eludiendo DAX por completo, entonces una solicitud GetItem realizada con el cliente de DAX dará un resultado distinto que si esa misma solicitud GetItem se lleva a cabo mediante el cliente de DynamoDB. Si esto sucede,DAX y DynamoDB contendrán valores inconsistentes de la misma clave hasta que venza el TTL del elemento de DAX.

Si una aplicación modifica los datos de una tabla de DynamoDB subyacente eludiendo DAX, la aplicación tendrá que prever y tolerar las inconsistencias de datos que surjan.

nota

Además de GetItem, el cliente de DAX también admite las solicitudes BatchGetItem. En esencia, BatchGetItem es un encapsulador que contiene una o varias solicitudes GetItem, de modo que DAX trata cada una de ellas como una operación GetItem individual.

Consistencia de escritura

DAX es una caché de escritura indirecta (write-through). Esto simplifica el proceso de mantener la consistencia entre la caché de elementos de DAX y las tablas de DynamoDB subyacentes.

El cliente de DAX admite las mismas operaciones de API de escritura que DynamoDB (PutItem, UpdateItem, DeleteItem, BatchWriteItem y TransactWriteItems). Cuando se utilizan estas operaciones con el cliente de DAX, los elementos se modifican tanto en DAX como en DynamoDB. DAX actualiza los elementos en la caché de elementos, con independencia del valor de TTL que tengan.

Por ejemplo, supongamos que emite una solicitud GetItem del cliente de DAX para leer un elemento de la tabla ProductCatalog. (La clave de partición es Id y no hay clave de ordenación). Recupera el elemento cuyo Id es 101. El valor de QuantityOnHand de ese elemento es 42. DAX almacena el elemento en su caché de elementos con un TTL específico. En este ejemplo, vamos a suponer que el TTL es de diez minutos. A continuación, 3 minutos más tarde, otra aplicación utiliza el cliente de DAX para actualizar el mismo elemento de modo que su valor de QuantityOnHand pasa a ser 41. suponiendo que el elemento no se vuelva a actualizar, todas las lecturas posteriores del mismo elemento que tengan lugar en los próximos 10 minutos devolverán el valor almacenado en caché de QuantityOnHand (41).

Procesamiento de escrituras en DAX

DAX está pensado para aplicaciones que requieren las lecturas de alto desempeño. Con el fin de transmitir las operaciones de escritura indirecta a través de la caché de DAX de forma síncrona, DynamoDB replica de forma automática y asíncrona las actualizaciones resultantes en la caché de elementos en todos los nodos del clúster. No es necesario administrar la lógica de invalidación de caché, porque DAX lo hace automáticamente.

DAX admite las siguientes operaciones de escritura: PutItem , UpdateItem, DeleteItem, BatchWriteItem y TransactWriteItems.

Cuando se envía una solicitud PutItem, UpdateItem, DeleteItem o BatchWriteItem a DAX, ocurre lo siguiente:

  • DAX envía la solicitud a DynamoDB.

  • DynamoDB responde a DAX para confirmar que la escritura se ha llevado a cabo correctamente.

  • DAX escribe el elemento en su caché de elementos.

  • DAX indica al solicitante que la escritura se ha realizado correctamente.

Cuando se envía una solicitud TransactWriteItems a DAX, ocurre lo siguiente:

  • DAX envía la solicitud a DynamoDB.

  • DynamoDB responde a DAX para confirmar que la transacción se ha completado.

  • DAX indica al solicitante que la escritura se ha realizado correctamente.

  • En segundo plano, DAX realiza una solicitud TransactGetItems para que cada elemento de la solicitud TransactWriteItems almacene el elemento en la caché de elementos. TransactGetItems se utiliza para garantizar un aislamiento serializable.

Si una escritura no se puede realizar en DynamoDB por cualquier motivo, incluida la limitación controlada, el elemento no se almacenará en caché en DAX. Se devuelve al solicitante la excepción correspondiente al error. De este modo se garantiza que los datos no se escriban en la caché de DAX a no ser que antes se hayan escrito correctamente en DynamoDB.

nota

Cada escritura en DAX altera el estado de la caché de elementos. Sin embargo, las escrituras en ella no afectan a la caché de consultas. La caché de elementos y la caché de consultas de DAX se utilizan con fines diferentes y funcionan de manera independiente una de la otra.

Comportamiento de la caché de consultas de DAX

DAX almacena en su caché de consultas los resultados de las solicitudes Query y Scan. Sin embargo, estos resultados no afectan en absoluto a la caché de elementos. Cuando la aplicación emite una solicitud Query o Scan con DAX, el conjunto de resultados se guarda en la caché de consultas, no en la de elementos.— No se puede "calentar" la caché de elementos antes de llevar a cabo una operación Scan, ya que la caché de elementos y la caché de consultas son entidades independientes.

Consistencia de consulta-actualización-consulta

Las actualizaciones de la caché de elementos o de la tabla de DynamoDB subyacente no invalidan ni modifican los resultados almacenados en la caché de consultas.

A modo de ejemplo, considere la siguiente situación. Una aplicación está trabajando con la tabla DocumentRevisions, que tiene una clave de partición DocId y una clave de ordenación RevisionNumber.

  1. Un cliente emite una operación Query para consultar el DocId 101 de todos los elementos cuyo valor de RevisionNumber sea mayor o igual que 5. DAX almacena el conjunto de resultados en la caché de consultas y se lo devuelve al usuario.

  2. El cliente emite una solicitud PutItem para DocId 101 con un valor RevisionNumber de 20.

  3. El cliente emite la misma operación Query que se describe en el paso 1 (DocId 101 y RevisionNumber >= 5).

En este caso, el conjunto de resultados almacenado en caché correspondiente a la operación Query emitida en el paso 3 es idéntico al que se almacenó en caché en el paso 1. El motivo es que DAX no invalida los conjuntos de resultados de Query o Scan cuando se actualizan elementos individuales. La operación PutItem del paso 2 solo se refleja en la caché de consultas de DAX cuando vence el TTL de la solicitud Query.

La aplicación debe tener en cuenta el valor de TTL de la caché de consultas y el tiempo durante el cual la aplicación puede tolerar resultados inconsistentes entre las cachés de consultas y de elementos.

Lecturas transaccionales y de consistencia alta

Para realizar una solicitud GetItem, BatchGetItem, Query o Scan de consistencia alta, debe establecer el parámetro ConsistentRead en true. DAX pasa las solicitudes de consistencia alta a DynamoDB. Cuando recibe una respuesta de DynamoDB, DAX devuelve los resultados al cliente, pero no almacena en caché los resultados. DAX no puede atender por sí solo a las lecturas de consistencia alta, porque no está estrechamente acoplado a DynamoDB. Debido a esto, todas las lecturas posteriores de DAX tendrían que ser lecturas consistentes finales, Y las lecturas de consistencia alta posteriores tendrían que pasarse a través de DynamoDB.

DAX administra las solicitudes TransactGetItems de la misma manera que administra las lecturas de consistencia alta. DAX pasa todas las solicitudes TransactGetItems a DynamoDB. Cuando recibe una respuesta de DynamoDB, DAX devuelve los resultados al cliente, pero no almacena en caché los resultados.

Almacenamiento en caché negativo

DAX admite las entradas de caché negativas, tanto en la caché de elementos como en la caché de consultas. Una entrada de caché negativa se produce cuando DAX no encuentra los elementos solicitados en una tabla de DynamoDB subyacente. En lugar de generar un error, DAX almacena en caché un resultado vacío y se lo devuelve al usuario.

Por ejemplo, supongamos que una aplicación envía una solicitud GetItem a un clúster de DAX, pero que no hay ningún elemento coincidente en la caché de elementos de DAX. Esto hacer que DAX lea el elemento correspondiente en la tabla de DynamoDB subyacente. Si el elemento tampoco está presente en DynamoDB, entonces DAX almacena un elemento vacío en su caché de elementos y, a continuación, devuelve este elemento vacío a la aplicación. Ahora, suponga que la aplicación envía otra solicitud GetItem al mismo elemento. DAX encuentra el elemento vacío en la caché del elemento y lo devuelve a la aplicación de inmediato. No consultará DynamoDB en absoluto.

Una entrada de caché negativa se conserva en la caché de elementos de DAX hasta que vence el TTL del elemento, se invoca su LRU o el elemento se modifica mediante PutItem, UpdateItem o DeleteItem.

La caché de consultas de DAX administra los resultados de caché negativos de forma similar. Si una aplicación realiza una operación Query o Scan y la caché de consultas de DAX no contiene un resultado en caché, DAX envía la solicitud a DynamoDB. Si no hay elementos coincidentes en el conjunto de resultados, DAX almacena un conjunto de resultados vacío en la caché de consultas y devuelve el conjunto de resultados vacío a la aplicación. Las solicitudes Query o Scan producen el mismo conjunto de resultados (vacío), hasta que vence su TTL.

Estrategias de escritura

El comportamiento de escritura indirecta (write-through) de DAX es adecuado para muchos patrones de aplicaciones. No obstante, existen algunos patrones de aplicación en los que este modelo de escritura indirecta podría no ser el adecuado.

En las aplicaciones que son sensibles a la latencia, la escritura a través de DAX genera un salto de red más. Por eso, la escritura en DAX es algo más lenta que si se realiza directamente en DynamoDB. Si la aplicación es sensible a la latencia de escritura, puede reducir esa latencia escribiendo directamente en DynamoDB. Para obtener más información, consulte Escritura directa.

Para las aplicaciones con gran intensidad de escritura (como las que llevan a cabo la carga de datos masivos), no es deseable escribir todos los datos a través de DAX, puesto que la aplicación solo leerá un pequeño porcentaje de ellos. Cuando se escriben grandes cantidades de datos a través de DAX, debe invocar el algoritmo LRU con el fin de dejar espacio en la caché para los nuevos elementos que hay que leer. Esto reduce la eficacia de DAX como caché de lectura.

Al escribir un elemento en DAX, el estado de la caché de elementos se modifica para dar cabida al nuevo elemento. Por ejemplo, DAX podría tener que expulsar datos antiguos de la caché de elementos con el fin de dejar espacio para el nuevo elemento. El nuevo elemento permanece en la caché de elementos, de conformidad con el algoritmo LRU y el ajuste de TTL de la caché. Mientras el elemento persista en la caché de elementos, DAX no volverá a leerlo en DynamoDB.

Escritura indirecta

La caché de elementos de DAX implementa una política de escritura indirecta. Para obtener más información, consulte Procesamiento de escrituras en DAX.

Cuando se escribe un elemento, DAX se asegura de que el elemento almacenado en caché esté sincronizado con el elemento presente en DynamoDB. Esto resulta útil para las aplicaciones que tienen que volver a leer un elemento inmediatamente después de escribirlo. Sin embargo, si otras aplicaciones escriben directamente en una tabla de DynamoDB, el elemento contenido en la caché de elementos de DAX dejará de estar sincronizada con DynamoDB.

Por ejemplo, tomemos dos usuarios (Alice y Bob) que están utilizando la tabla ProductCatalog. Alice obtiene acceso a la tabla mediante DAX, pero Bob elude DAX y obtiene acceso a la tabla directamente en DynamoDB.


                    Diagrama de flujo de trabajo que muestra pasos con números sobre cómo los usuarios Alice y Bob obtienen acceso a una tabla mediante DAX y DynamoDB.
  1. Alice actualiza un elemento de la tabla ProductCatalog. DAX reenvía la solicitud a DynamoDB y la actualización se lleva a cabo correctamente. Después, DAX escribe el elemento en su caché de elementos y devuelve una respuesta correcta a Alice. A partir de ese momento, hasta que el elemento se expulse definitivamente de la caché, cualquier usuario que lo lea en DAX ve el elemento con la actualización de Alice.

  2. Poco después, Bob actualiza el mismo elemento ProductCatalog en el que Alice ha escrito. Sin embargo, Bob actualiza el elemento directamente en DynamoDB. DAX no actualiza automáticamente su caché de elementos en respuesta a las actualizaciones a través de DynamoDB. Por tanto, los usuarios de DAX no verán la actualización de Bob.

  3. Alice vuelve a leer el elemento en DAX. Este elemento se encuentra en la caché del elementos, por lo que DAX se lo devuelve a Alice sin obtener acceso a la tabla de DynamoDB.

En este caso, Alice y Bob obtienen representaciones distintas del mismo elemento ProductCatalog. Esto continuará siendo así hasta que DAX expulse el elemento de la caché de elementos o hasta que otro usuario lo vuelva a actualizar mediante DAX.

Escritura directa

Si la aplicación tiene que escribir grandes cantidades de datos (por ejemplo, en una carga de datos masivos), puede ser más lógico eludir DAX y escribir los datos directamente en DynamoDB. Esta estrategia de escritura directa (write-around) reduce la latencia. Sin embargo, la caché de elementos no se mantendrá sincronizada con los datos de DynamoDB.

Si decide utilizar una estrategia de escritura directa, recuerde que DAX rellena su caché de elementos cada vez que las aplicaciones utilizan el cliente de DAX para leer los datos. Esto puede ser beneficioso en algunos casos, ya que garantiza que solo se almacenen en caché los datos que se leen con mayor frecuencia (en lugar de los datos que se escriben con mayor frecuencia).

Suponga, por ejemplo, que un usuario (Charlie) desea trabajar con una tabla diferente, la tabla GameScores, mediante DAX. La clave de partición de GameScores es UserId, por lo que todas las puntuaciones de Charlie tendrían el mismo UserId.


                    Diagrama de flujo de trabajo que muestra los pasos con números relativos a cómo Charlie trabaja con una tabla de DynamoDB utilizando DAX.
  1. Charlie desea recuperar todas sus puntuaciones, por lo que envía una solicitud Query a DAX. Suponiendo que esta consulta no se haya emitido antes, DAX se la reenvía a DynamoDB para procesarla. Almacena los resultados en la caché de consultas de DAX y, por último, devuelve los resultados a Charlie. El conjunto de resultados seguirá disponible en la caché de consultas hasta que se expulse.

  2. Ahora, supongamos que Charlie juega a Blasters Meteor y logra una puntuación máxima. Charlie envía una solicitud UpdateItem a DynamoDB para modificar un elemento en la tabla GameScores.

  3. Por último, Charlie decide volver a ejecutar la operación Query anterior para recuperar todos sus datos de GameScores. Charlie no ve su puntuación máxima en Meteor Blasters en los resultados. Esto se debe a que los resultados de la consulta proceden de la caché de consultas, no de la caché de elementos. Las dos cachés son independientes entre sí, de modo que un cambio en una de ellas no afecta a la otra.

DAX no actualiza los conjuntos de resultados de la caché de consultas con los datos más recientes de DynamoDB. Cada conjunto de resultados de la caché de consultas estaba actualizado en el momento de ejecutar la operación Query o Scan. Por lo tanto, los resultados que Charlie obtiene con la operación Query no reflejan su operación PutItem. Esto seguirá siendo así hasta que DAX expulse el conjunto de resultados de la caché de consultas.