App Engine高复制数据存储

14

我是完全的App Engine新手,我想确认自己对高复制数据存储的理解。

文档说实体组是“一致性单位”,所有数据最终都是一致的。同样,在同一行中,它还指出“跨实体组的查询可能过时”。

可以有人举几个查询可能会“过时”的例子吗?它是否意味着我可能在没有任何父项(即其自己的组)的情况下保存实体,然后很快就查询它,但找不到它?这是否意味着如果我希望数据始终100%更新,我需要将它们全部保存在同一个实体组中?

针对这种情况,常见的解决方法是使用memcache缓存实体,时间长于数据在所有数据中心中变得一致所需的平均时间。这方面的大致延迟是多少?

谢谢

3个回答

18

这是说我可能会保存一个没有任何父级(即它自己的组)的实体,然后很快查询它,但找不到它吗?

正确。从技术上讲,在常规的主从数据存储中也是如此,因为索引是异步更新的,但在实践中,这种情况发生的时间非常短,你几乎看不到。

如果您的“查询”是指“按键获取”,那么无论哪种实现方式,它始终会返回强一致性的结果。

这是否也意味着,如果我希望数据始终保持100%最新状态,我需要将它们全部保存在同一个实体组中?

在回答之前,您需要定义“100%最新”的含义。

这个常见的解决方法是使用memcache来缓存实体,缓存时间比所有数据中心内数据变得一致所需的平均时间长吗?

不是。Memcache严格用于提高访问速度;您不应在缓存逐出会导致问题的任何情况下使用它。

如果您需要保证正在查看最新版本,则始终可以使用强一致性的获取。但是,如果没有具体的示例来说明您要做什么,很难提供建议。


1
很抱歉,我没有一个具体的例子。我正在努力学习这个系统,以便开始我的项目工作。我只想能够在数据存储中存储数据,并在需要时检索最新版本。我只是试图弄清楚什么情况下不是这种情况,以及如何确保当我查询结果时,我会得到最新的结果。通过“查询”,我指的是像在SQL中一样按属性进行查询,而不是按键进行查询。我只是想了解祖先组是“一致性单位”是什么意思,以及什么可能是“不一致”的。 - amatsukawa
尼克在这份文档的使用注意事项部分中指出:“你可以将最近的帖子放入具有过期时间的memcache中,然后从memcache和从数据存储检索到的帖子混合显示。”。该文档链接为:http://code.google.com/intl/en/appengine/docs/python/datastore/hr/overview.html - fjsj
@user439383(您是否考虑设置一个更有用的用户名?)个人认为,在没有特定情况需要时,不必过于担心这个问题。对于大多数情况来说,最终一致性语义是可以接受的,而当您需要强一致性时,您会知道的。 - Nick Johnson
1
很好的回答,Nick。我只是想确认一下你说的话。“如果你的意思是通过键获取查询,那么在任何实现中都将始终返回强一致的结果。”。所以,如果我执行:MyNDBModal.get_by_id(theID),即使它是最近写入的,我也会总是找到它吗? - Mazyod

11

必要的博客示例设置; 作者文章

class Author(db.Model):
    name = db.StringProperty()

class Post(db.Model):
    author = db.ReferenceProperty()
    article = db.TextProperty()

bob = Author(name='bob')
bob.put()

首先要记住的是,正常的对单个实体组(包括单个实体)进行的get/put/delete操作将按预期工作:

post1 = Post(article='first article', author=bob)
post1.put()

fetched_post = Post.get(post1.key())
# fetched_post is latest post1

只有在跨多个实体组进行查询时,您才能注意到不一致性。除非指定了parent属性,否则所有实体都在单独的实体组中。因此,如果在bob创建帖子后立即查看自己的帖子很重要,则应小心处理以下内容:

fetched_posts = Post.all().filter('author =', bob).fetch(x)
# fetched_posts _might_ contain latest post1

fetched_posts 可能 包含来自 bob 的最新的 post1,但也可能不包含。这是因为所有的 Posts 不在同一个实体组中。当在HR中进行此类查询时,您应该考虑像这样思考:“为我获取Bob最新发布的帖子”

由于我们的应用程序中重要的一点是作者在创建后能够直接在列表中看到自己的文章,所以我们将使用 parent 属性将它们绑在一起,并使用 ancestor 查询仅从该组内获取文章:

post2 = Post(parent=person, article='second article', author=bob)
post2.put()

bobs_posts = Post.all().ancestor(bob.key()).filter('author =', bob).fetch(x)

现在我们知道post2将会在我们的bobs_posts结果中。

如果我们的查询目的是获取“可能是所有最新的帖子+一定是Bob的最新帖子”,那么我们需要执行另一个查询。

other_posts = Post.all().fetch(x)

然后将结果other_postsbobs_posts合并在一起,以获得所需的结果。


这实际上是一个很好的解释。我唯一不理解的是你例子中的 person 是什么?是类还是实例? - Houman

5
刚刚将我的应用从主/从数据存储迁移到高可靠性数据存储,我必须说,在实践中,最终一致性对大多数应用程序来说并不是问题。
考虑经典的留言板示例,您可以put()一个新的留言板帖子实体,然后立即查询留言板中的所有帖子。使用高可靠性数据存储,您将在几秒钟后(在Google I/O上,Google工程师表示滞后时间大约为2-5秒)才能看到查询结果中出现新帖子。
现实中,您的留言板应用程序可能正在执行新留言板帖子条目的AJAX提交。提交新帖子后,无需重新获取所有帖子。Web应用程序可以在AJAX请求成功后将新条目插入UI。当用户离开网页并返回或甚至点击浏览器刷新按钮时,几秒钟已经过去,很可能新帖子将在检索所有留言板帖子的查询中返回。
最后,请注意,最终一致性性能仅适用于查询。如果您put()一个实体并立即调用db.get()将其取回,则结果是强一致的,即您将获得实体的最新快照。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接