给Google App Engine(Java)实体一个父实体能保证一致性吗?

给Google App Engine(Java)实体一个父实体能保证一致性吗?,java,google-app-engine,google-cloud-datastore,Java,Google App Engine,Google Cloud Datastore,我有一个Java风格的GoogleAppEngine应用程序,在这里我需要经过多次读取,然后将数据写入数据存储。每个周期取决于是否能够从上次写入中读取最新数据 阅读Google文档,似乎保证这种行为的方法是将创建的实体绑定到一个公共父级,即新的Entityentity,parentKey 这里的问题是,使用相同的祖先父实体编写实体真的能保证一致性吗?父实体似乎与子实体有着相同的问题——不同的数据存储中可能存在多个实例。对此,我们非常感谢您的澄清 保证这种行为的方法似乎是将创建的实体绑定到公共父级

我有一个Java风格的GoogleAppEngine应用程序,在这里我需要经过多次读取,然后将数据写入数据存储。每个周期取决于是否能够从上次写入中读取最新数据

阅读Google文档,似乎保证这种行为的方法是将创建的实体绑定到一个公共父级,即新的Entityentity,parentKey

这里的问题是,使用相同的祖先父实体编写实体真的能保证一致性吗?父实体似乎与子实体有着相同的问题——不同的数据存储中可能存在多个实例。对此,我们非常感谢您的澄清

保证这种行为的方法似乎是将创建的实体绑定到公共父级,即新的Entityentity、parentKey

正确,这使子实体属于同一实体组

父实体似乎与子实体有着相同的问题——不同的数据存储中可能存在多个实例

这也是正确的。每个根实体(即本身没有父实体的实体)都属于自己的实体组

我解决这个问题的方法是对数据库进行建模,使当前处理周期中所需的所有数据共享同一个实体组,并在事务中对其进行读/写操作,以便仍然能够在某种程度上保持并发性,比如在不同的实例上处理不同的用户,每个用户的所有数据都位于同一组中

如果您需要同时处理同一类型的所有实体(如快照),恐怕AppEngine的数据存储并非最佳选择。您可以让所有实体都是硬编码根实体的子实体,如下所示:

Key root = KeyFactory.createKey(kind, "root");
new Entity(entity, root);

它可以工作,但它带来了很多问题——主要的一个问题是,它会减慢你的应用程序的速度,因为你不能同时执行许多写入操作。您可以阅读更多信息。

使用相同的祖先父实体编写实体确实可以保证一致性

怎么做

您想知道这是怎么回事:似乎父实体和子实体会有相同的问题——多个实例可能存在于不同的数据存储中

答案是有一个非常复杂的算法google for Megastore papers和PAXOS算法,如果您对在实体组上实现ACID事务的技术细节感兴趣,即使实体在不同的机器上

为什么要将ACID限制为实体组

您可能想知道为什么他们不为整个数据存储区这样做。看起来他们已经解决了如何在分布式实体上执行ACID事务,那么为什么不在不考虑实体分组的情况下实现它呢

答案是ACID事务是有成本的,成本是这样的:每秒最多只能对一个实体组进行5次写入实际上更像是每秒5次写入事务,因此可以批量写入相同的事务以获得更好的写入吞吐量。因此,如果他们对整个数据库都这样做,那么对于他们所追求的互联网规模来说,这几乎是无用的

写了之后再读明白了:

作为旁注,如果在同一事务中修改了实体之后才阅读该实体,则必须小心。数据存储事务的语义是这样的:读操作可以看到事务开始时出现的数据。这意味着它不会看到事务内部发生的写操作

推荐阅读好,观看好


如果您正在使用数据存储,这几乎是一个必须观看的视频。它将为您解决许多问题:

注意,使用CA单实体组不仅会降低速度,还会限制您可以在其中保存的总数据量。@ZigMandel。这是不正确的。对于单个实体组中的总数据,没有超出数据存储配额限制的限制。唯一的限制是写吞吐量。如果你愿意的话,我可以把文档挖出来,但是他们对此非常明确。在文档中的某个地方,它说将实体组大小限制为用户的数据。数据不会被分割,所以应该有一个大小限制。我几年前读过它,所以知道它就在某个地方:文档建议保持实体组不大于单个用户的数据@ZigMandel。您误解了文档。您所指的部分是建议您保持实体组较小,因为写入吞吐量限制争用。如果写入吞吐量很小,则可以在单个实体组中存储所需的数据。这里有一个指向Google I/O talk的链接,该链接明确指出,实体组可以在6:16时具有任意大小: