Estructurar los datos para lograr una coherencia sólida

Cloud Datastore proporciona alta disponibilidad, escalabilidad y durabilidad mediante la distribución de datos en muchas máquinas y el uso de una replicación síncrona sin instancia maestra en un área geográfica amplia. Sin embargo, este diseño presenta la desventaja de que el rendimiento de las operaciones de escritura de cualquier grupo de entidad se limita a aproximadamente una confirmación por segundo, y también hay limitaciones para las consultas o las transacciones que pueden alcanzar varios grupos de entidad. En esta página se describen esas limitaciones en mayor profundidad y se analizan las recomendaciones para estructurar los datos a fin de lograr una coherencia sólida y cumplir con los requisitos de rendimiento de escritura de la aplicación.

Las lecturas de coherencia sólida siempre muestran datos actuales y, si se realizan dentro de una transacción, parecerán provenir de una única instantánea coherente. Sin embargo, las consultas deben especificar un filtro de principal para tener coherencia sólida o participar en una transacción, y las transacciones pueden involucrar un máximo de 25 grupos de entidad. Las lecturas con coherencia eventual no tienen esas limitaciones y son adecuadas en muchos casos. Utilizar lecturas con coherencia eventual puede permitirte distribuir los datos entre más grupos de entidad, lo que hace posible obtener una mayor capacidad de procesamiento de escritura a través de la ejecución de confirmaciones en paralelo en los distintos grupos de entidad. Sin embargo, debes comprender las características de las lecturas con coherencia eventual a fin de determinar si son adecuadas para tu aplicación:

  • Los resultados obtenidos de estas lecturas pueden no reflejar las transacciones más recientes. Esto puede suceder porque esas lecturas no se aseguran de que la réplica sobre la que se ejecutan esté actualizada. En cambio, utilizan cualquier dato disponible en esa réplica cuando se ejecuta la consulta. La latencia de replicación es casi siempre inferior a unos pocos segundos.
  • Puede parecer que una transacción confirmada en varias entidades se aplicó solo a algunas de ellas. Sin embargo, ten en cuenta que nunca parecerá que una transacción se aplicó parcialmente dentro de una sola entidad.
  • Los resultados de una consulta pueden tener entidades que no deberían haberse incluido según los criterios del filtro y es posible que se excluyan entidades que sí deberían haberse incluido. Esto puede ocurrir porque los índices pueden leerse en una versión diferente de la que se lee en la entidad.

Si deseas comprender cómo estructurar tus datos para una coherencia sólida, compara dos enfoques diferentes correspondientes a una aplicación de libro de visitas simple. El primer enfoque crea una nueva entidad raíz para cada entidad:

Java 8

protected Entity createGreeting(
    DatastoreService datastore, User user, Date date, String content) {
  // No parent key specified, so Greeting is a root entity.
  Entity greeting = new Entity("Greeting");
  greeting.setProperty("user", user);
  greeting.setProperty("date", date);
  greeting.setProperty("content", content);

  datastore.put(greeting);
  return greeting;
}

Java 7

protected Entity createGreeting(
    DatastoreService datastore, User user, Date date, String content) {
  // No parent key specified, so Greeting is a root entity.
  Entity greeting = new Entity("Greeting");
  greeting.setProperty("user", user);
  greeting.setProperty("date", date);
  greeting.setProperty("content", content);

  datastore.put(greeting);
  return greeting;
}

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

Java 8

protected List<Entity> listGreetingEntities(DatastoreService datastore) {
  Query query = new Query("Greeting").addSort("date", Query.SortDirection.DESCENDING);
  return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));
}

Java 7

protected List<Entity> listGreetingEntities(DatastoreService datastore) {
  Query query =
      new Query("Greeting")
          .addSort("date", Query.SortDirection.DESCENDING);
  return datastore.prepare(query)
      .asList(FetchOptions.Builder.withLimit(10));
}

Sin embargo, debido a que usas una consulta no principal, es posible que la réplica utilizada para realizar la consulta en este esquema no haya visto el nuevo saludo en el momento en que se ejecuta la consulta. No obstante, casi todas las escrituras estarán disponibles para consultas no principales pocos segundos después de su confirmación. En el caso de muchas aplicaciones, una solución que proporcione los resultados de una consulta no principal en el contexto de los cambios propios del usuario actual será generalmente suficiente para hacer que las latencias de replicación sean completamente aceptables.

Si es importante que tu aplicación tenga coherencia sólida, un enfoque alternativo es escribir entidades con una ruta de acceso principal que identifique la misma entidad raíz en todas las entidades que deben leerse en una consulta principal única con coherencia sólida:

Java 8

protected Entity createGreeting(
    DatastoreService datastore, User user, Date date, String content) {
  // String guestbookName = "my guestbook"; -- Set elsewhere (injected to the constructor).
  Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);

  // Place greeting in the same entity group as guestbook.
  Entity greeting = new Entity("Greeting", guestbookKey);
  greeting.setProperty("user", user);
  greeting.setProperty("date", date);
  greeting.setProperty("content", content);

  datastore.put(greeting);
  return greeting;
}

Java 7

protected Entity createGreeting(
    DatastoreService datastore, User user, Date date, String content) {
  // String guestbookName = "my guestbook"; -- Set elsewhere (injected to the constructor).
  Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);

  // Place greeting in the same entity group as guestbook.
  Entity greeting = new Entity("Greeting", guestbookKey);
  greeting.setProperty("user", user);
  greeting.setProperty("date", date);
  greeting.setProperty("content", content);

  datastore.put(greeting);
  return greeting;
}

Después podrás realizar una consulta principal de coherencia sólida dentro del grupo de identidad identificado por la entidad raíz común.

Java 8

protected List<Entity> listGreetingEntities(DatastoreService datastore) {
  Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
  Query query =
      new Query("Greeting", guestbookKey)
          .setAncestor(guestbookKey)
          .addSort("date", Query.SortDirection.DESCENDING);
  return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));
}

Java 7

protected List<Entity> listGreetingEntities(DatastoreService datastore) {
  Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
  Query query =
      new Query("Greeting", guestbookKey)
          .setAncestor(guestbookKey)
          .addSort("date", Query.SortDirection.DESCENDING);
  return datastore.prepare(query)
      .asList(FetchOptions.Builder.withLimit(10));
}

Este enfoque logra una coherencia sólida por medio de la escritura en un solo grupo de entidad por libro de visitas, pero también limita los cambios al libro de visitas a no más de 1 escritura por segundo (el límite admitido para los grupos de entidad). Si es probable que tu aplicación tenga un uso de escritura más intenso, podría ser conveniente que uses otros medios: Por ejemplo, puedes colocar publicaciones recientes en Memcache con vencimiento y mostrar una combinación de publicaciones recientes de Memcache y Cloud Datastore, o podrías almacenarlas en caché en una cookie, poner algún estado en la URL, o algo completamente distinto. El objetivo es encontrar una solución de almacenamiento en caché que le brinde datos al usuario actual durante el período en que el usuario publica en tu aplicación. Recuerda que si haces una operación get, una consulta principal o cualquier operación dentro de una transacción, siempre verás los datos escritos más recientemente.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java