Modelos de coherencia 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.
Temas
Coherencia 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 un nodo). 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 eventualmente consistente 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 presenta dos memorias caché diferentes, una caché de elemento y una caché de consulta. Para obtener más información, consulte DAX: cómo funciona.
En esta sección se abordan las implicaciones para la consistencia de la lectura y la escritura en la caché de elemento de DAX.
Coherencia de lectura
De forma predeterminada, con DynamoDB la operación GetItem
lleva a cabo una lectura eventualmente consistente. 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 utiliza GetItem
con el cliente de DAX, la operación (en este caso, una lectura eventualmente consistente) se lleva a cabo como se muestra a continuación.
-
El cliente de DAX emite una solicitud
GetItem
. DAX intenta leer el elemento solicitado en la caché de elemento. Si el elemento está presente en la caché (acierto de caché), DAX se lo devuelve a la aplicación. -
Si el elemento no está disponible (error de caché), DAX realiza una operación
GetItem
de consistencia final en DynamoDB. -
DynamoDB devuelve el elemento solicitado y DAX lo almacena en la caché de elemento.
-
DAX devuelve el elemento a la aplicación.
-
(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 elemento permanecerá en la caché de elemento de DAX, sujeto a la configuración del período de vida (TTL) y el algoritmo de elementos menos usados recientemente (LRU) 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 por completo a DAX, 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 para 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 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.
Coherencia de escritura
DAX es una caché de escritura indirecta (write-through). Esto simplifica el proceso de mantener la consistencia entre la caché de elemento 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 actualizará los elementos en la caché de elemento, independientemente 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 QuantityOnHand
para ese elemento es 42
. DAX almacena el elemento en su caché de elemento con un TTL concreto. 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 forma 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 diez minutos devolverán el valor de QuantityOnHand
almacenado en caché (41
).
Cómo procesa DAX las escrituras
DAX está pensado para aplicaciones que requieren lecturas de alto rendimiento. Como caché de escritura indirecta, DAX pasa las escrituras a DynamoDB de forma sincrónica y, a continuación, replica de forma automática y asíncrona las actualizaciones resultantes a la caché de elemento 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 elemento.
-
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 en la solicitudTransactWriteItems
almacene el elemento en la caché de elemento.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 elemento. Sin embargo, las escrituras en ella no afectan a la caché de consultas. (La caché de elemento y la caché de consulta de DAX se utilizan con fines diferentes y operan de manera independiente una de la otra).
Comportamiento de la caché de consulta de DAX
DAX almacena en su caché de consulta 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 consulta, no en la de elemento. 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.
Coherencia 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
.
-
Un cliente emite una
Query
paraDocId
101
, para todos los elementos conRevisionNumber
mayor o igual que5
. DAX almacena el conjunto de resultados en la caché de consulta y se lo devuelve al usuario. -
El cliente emite una solicitud
PutItem
paraDocId
101
con un valor deRevisionNumber
de20
. -
El cliente emite la misma operación
Query
que se describe en el paso 1 (DocId
101
yRevisionNumber
>=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 consulta de DAX cuando vence el TTL de la 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 altamente coherentes y transaccionales
Para realizar una solicitud de lectura fuertemente consistente GetItem
, BatchGetItem
, Query
o Scan
, debe establecer el parámetro ConsistentRead
en true (verdadero). DAX pasa las solicitudes de lectura fuertemente consistentes 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 fuertemente consistentes, porque no está estrechamente acoplado a DynamoDB. Debido a esto, todas las lecturas posteriores de DAX tendrían que ser lecturas eventualmente consistentes. Y las lecturas fuertemente consistentes posteriores tendrían que pasarse a través de DynamoDB.
DAX administra las solicitudes TransactGetItems
de la misma manera que administra las lecturas fuertemente consistentes. 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 elemento como en la caché de consulta. 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 elemento de DAX. Esto hace 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 elemento y, a continuación, devuelve este elemento vacío a la aplicación. Ahora, supongamos que la aplicación envía otra solicitud GetItem
para obtener el mismo elemento. DAX encontrará el elemento vacío en la caché de elemento y se lo devolverá de inmediato a la aplicación. No consultará DynamoDB en absoluto.
Una entrada de caché negativa se conserva en la caché de elemento 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 consulta 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 consulta 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 consulta 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 elemento se modifica para dar cabida al nuevo elemento. (Por ejemplo, DAX podría tener que expulsar datos antiguos de la caché de elemento con el fin de dejar espacio para el nuevo elemento). El nuevo elemento permanecerá en la caché de elementos, de conformidad con el algoritmo LRU y el ajuste de TTL de esta última. Mientras el elemento persista en la caché de elemento, DAX no volverá a leerlo en DynamoDB.
Escritura indirecta
La caché de elemento de DAX implementa una política de escritura indirecta. Para obtener más información, consulte Cómo procesa DAX las escrituras.
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 elemento 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.
-
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 elemento 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. -
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 elemento en respuesta a las actualizaciones a través de DynamoDB. Por tanto, los usuarios de DAX no verán la actualización de Bob. -
Alice vuelve a leer el elemento en DAX. Este elemento se encuentra en la caché del elemento, 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 elemento 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 elemento no se mantendrá sincronizada con los datos de DynamoDB.
Si decide utilizar una estrategia de escritura directa, recuerde que DAX rellena su caché de elemento 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
.
-
Charlie desea recuperar todas sus puntuaciones, por lo que envía una
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 consulta 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. -
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 tablaGameScores
. -
Por último, Charlie decide volver a ejecutar la operación
Query
anterior para recuperar todos sus datos deGameScores
. 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 consulta 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 consulta.