Estructurar datos para una coherencia inmediata

Datastore ofrece alta disponibilidad, escalabilidad y durabilidad distribuyendo los datos en muchas máquinas y usando la replicación síncrona en una amplia zona geográfica. Sin embargo, este diseño tiene una desventaja: el rendimiento de escritura de cualquier grupo de entidades se limita a una confirmación por segundo, y hay limitaciones en las consultas o transacciones que abarcan varios grupos de entidades. En esta página se describen estas limitaciones con más detalle y se explican las prácticas recomendadas para estructurar los datos de forma que se admita una coherencia sólida y, al mismo tiempo, se cumplan los requisitos de rendimiento de escritura de la aplicación.

Las lecturas con coherencia fuerte siempre devuelven datos actuales y, si se realizan en una transacción, parecerá que proceden de una única instantánea coherente. Sin embargo, las consultas deben especificar un filtro de ancestro para tener una coherencia sólida o participar en una transacción, y las transacciones pueden incluir un máximo de 25 grupos de entidades. Las lecturas con coherencia final no tienen esas limitaciones y son adecuadas en muchos casos. Si usas lecturas con coherencia final, puedes distribuir tus datos entre un mayor número de grupos de entidades, lo que te permite obtener un mayor rendimiento de escritura ejecutando confirmaciones en paralelo en los diferentes grupos de entidades. Sin embargo, debes conocer las características de las lecturas con coherencia final para determinar si son adecuadas para tu aplicación:

  • Es posible que los resultados de estas lecturas no reflejen las últimas transacciones. Esto puede ocurrir porque estas lecturas no aseguran que la réplica en la que se ejecutan esté actualizada. En su lugar, utilizan los datos disponibles en esa réplica en el momento de la ejecución de la consulta. La latencia de replicación es casi siempre inferior a unos segundos.
  • Una transacción confirmada que abarcaba varias entidades podría parecer que se ha aplicado a algunas de las entidades y no a otras. Sin embargo, ten en cuenta que nunca parecerá que una transacción se ha aplicado parcialmente en una sola entidad.
  • Los resultados de la consulta pueden incluir entidades que no deberían haberse incluido según los criterios de filtro y pueden excluir entidades que sí deberían haberse incluido. Esto puede ocurrir porque los índices se pueden leer en una versión diferente a la de la propia entidad.

Para saber cómo estructurar tus datos para conseguir una coherencia inmediata, compara dos enfoques diferentes para una aplicación de libro de visitas sencilla. El primer método crea una nueva entidad raíz por cada entidad que se crea:

g := Greeting{ /* ... */ }
key := datastore.NewIncompleteKey(ctx, "Greeting", nil)

A continuación, consulta el tipo de entidad Greeting para obtener los diez saludos más recientes.

q := datastore.NewQuery("Greeting").Order("-Date").Limit(10)

Sin embargo, como estás usando una consulta que no es de ancestro, es posible que la réplica usada para realizar la consulta en este esquema no haya visto el nuevo saludo cuando se ejecute la consulta. Sin embargo, casi todas las escrituras estarán disponibles para las consultas que no sean de ancestros en cuestión de segundos después de la confirmación. En muchas aplicaciones, una solución que proporcione los resultados de una consulta que no sea de ancestro en el contexto de los cambios del usuario actual suele ser suficiente para que las latencias de replicación sean completamente aceptables.

Si la coherencia sólida es importante para tu aplicación, puedes escribir entidades con una ruta de ancestro que identifique la misma entidad raíz en todas las entidades que se deben leer en una sola consulta de ancestro con coherencia sólida:

g := Greeting{ /* ... */ }
key := datastore.NewIncompleteKey(ctx, "Greeting", guestbookKey(ctx))

A continuación, podrá realizar una consulta de ancestro con coherencia fuerte en el grupo de entidades identificado por la entidad raíz común:

q := datastore.NewQuery("Greeting").Ancestor(guestbookKey(ctx)).Order("-Date").Limit(10)

Con este enfoque se consigue una coherencia sólida escribiendo en un solo grupo de entidades por libro de visitas, pero también se limita el número de cambios que se pueden hacer en el libro de visitas a una escritura por segundo (el límite admitido para los grupos de entidades). Si es probable que tu aplicación tenga un uso más intenso de escritura, puede que tengas que usar otros medios. Por ejemplo, puedes poner las publicaciones recientes en una memcache con una fecha de vencimiento y mostrar una combinación de publicaciones recientes de la memcache y Datastore. También puedes almacenarlas en caché en una cookie, poner algún estado en la URL o hacer otra cosa. El objetivo es encontrar una solución de almacenamiento en caché que proporcione los datos del usuario actual durante el periodo en el que el usuario publique contenido en tu aplicación. Recuerda que, si haces una solicitud GET, una consulta de ancestros o cualquier operación dentro de una transacción, siempre verás los datos escritos más recientemente.