我有一个Java风格的Google App Engine应用程序,我需要经历多个阅读周期,然后将数据写入数据存储区。每个周期取决于能够从最后写入中读取最新数据。
阅读Google文档,似乎保证此行为的方法是将创建的实体绑定到公共父级,即新实体(entity,parentKey)。
这里的问题是编写具有相同祖先(父)实体的实体是否确实保证了一致性?似乎父实体与子节点具有相同的问题 - 多个实例可能存在于不同的数据存储区中。对此的清晰度非常感谢。
答案 0 :(得分:0)
使用相同的祖先(父)实体编写实体 DOES 确实保证了一致性。
如何吗
你想知道这是怎么回事:“看起来父实体会和孩子们有同样的问题 - 多个实例可能存在于不同的数据存储中。”
答案是,有一个非常复杂的算法(谷歌用于Megastore论文,PAXOS算法,如果你对技术细节感兴趣)在实体组上实现ACID交易,即使实体在不同的机强>!
为什么要将ACID限制为实体组?
您可能想知道为什么他们不为整个数据存储区执行此操作。看起来他们想出了如何对分布的实体进行ACID事务,那么为什么不实现它而不管实体分组?
的答案是ACID事务是有代价的,成本是这样的:每秒最多只能写入一个实体组5次(实际上更像是每秒写入5次事务,因此可以在同一事务中批量写入以获得更好的写入吞吐量)。因此,如果他们为整个数据库执行此操作,那么对于他们所针对的互联网规模来说实际上是无用的。
写完背后阅读:
作为旁注,如果您在修改实体后(在同一事务中)读取实体,则必须小心。数据存储区事务的语义是这样的,即读取数据显示在事务的 start 处。这意味着它不会看到事务中发生的写入。
推荐阅读(好,观看)
如果您正在使用数据存储区,这几乎是需要观看的视频。它会为您解决很多这些问题:Google I/O 2011: More 9s Please: Under The Covers of the High Replication Datastore
答案 1 :(得分:-1)
似乎保证此行为的方法是将创建的实体绑定到公共父级,即新实体(entity,parentKey)。
正确,这使子实体属于同一个实体组。
似乎父实体与子节点具有相同的问题 - 多个实例可能存在于不同的数据存储区中。
这也是正确的。每个根实体(即没有父本身的实体)属于其自己的实体组。
我解决这个问题的方法是对数据库进行建模,使当前处理周期所需的所有数据共享同一个实体组,并在事务上读/写它,以便仍然能够在某种程度上维护并发性(类似于“在不同实例上处理不同用户”之类的内容,其中每个用户的所有数据都在同一个组中。)
如果你需要同时处理所有类型的实体,比如在快照中,我担心AppEngine的数据存储不是真正的最佳选择。您可以让所有实体成为硬编码root
之类的孩子:
Key root = KeyFactory.createKey(kind, "root");
new Entity(entity, root);
它可以工作,但它带来了很多问题 - 主要的一点是它会减慢你的应用程序,因为你不能一次执行多次写入。您可以阅读更多相关信息here。