NDB删除&一致性

时间:2017-03-20 21:17:20

标签: google-app-engine google-cloud-datastore

我知道NDB查询(阅读)最终是一致的。但删除和写作呢?

例如,运行以下代码始终(最终)会导致我们的数据存储区中存在一个有缺陷的小部件:

# get rid of defective widgets
defective_widgets = Widget.query(Widget.defective == True).fetch(keys_only=True)
ndb.delete_multi(defective_widgets)

# uh oh, we have a new one
Widget(defective=True).put()

...或者删除操作是否有可能删除新的有缺陷的小部件?

2 个答案:

答案 0 :(得分:1)

" ...删除操作是否有可能删除新的有缺陷的小部件?"

"将始终(最终)运行以下代码导致我们的数据存储区中存在一个有缺陷的小部件"

同样不可以。以前有可能没有删除有缺陷的小部件。

Cloud Datastore在查找(按键获取)和祖先查询方面非常一致。它最终在非祖先查询上是一致的。考虑Cloud Datastore如何处理一致性的方法是:

  • 实体写入被同步写入/删除
  • 索引是异步更新的(大部分时间是立即,但并非总是如此)
  • 实体组定义数据位置,因此祖先查询强制强一致性

让我们看一下你的例子

为了论证,让我们设置一个开始的样本数据集。一些代码添加了新的有缺陷的小部件:

WidgetA(defective=True).put()
WidgetB(defective=True).put()
WidgetC(defective=True).put()

现在我们有:

  • WidgetA(defective: True)
  • WidgetB(defective: True)
  • WidgetC(defective: True)

进行查找(按键获取)将始终返回这3个实体,因为查找非常一致。

在添加这3个小部件后,一些代码想立即获取所有有缺陷小部件的列表。

defective_widgets = Widget.query(Widget.defective == True).fetch(keys_only=True)

然后发出删除所有内容的电话:

ndb.delete_multi(defective_widgets)

我们现在在数据库中有哪些数据?答案是WidgetA,B和&的任意组合。 C,或者没有,甚至全部。为什么?因为发出的查询最终是一致的,并且取决于索引更新是否适用,但确定defective_widgets中是否有实体键列表。

所以此时,在最终执行Widget(defective=True).put()之后,我们的数据库中可能会有1到4个有缺陷的小部件。

你怎么能避免这种情况?

选项1(实体组):如果有缺陷的小部件总是以每秒1个事务或更低的速率写入/更新,那么您可以将它们全部放在一个实体组中,修改您的查询是一个祖先查询=然后一切都将最终一致。注意:如果您可以在事务中一起批量窗口小部件写入/更新,则所有这些写入仅计为1个事务,因此,将500个窗口小部件一起批处理允许您每秒执行500个窗口小部件。

选项2(软删除):如果写入速率很高,则可以实现软删除系统。单个实体(缓存,让我们称之为"版本实体")存储单调递增的版本号(整数)。所写的任何新缺陷小部件也会将此号码存储在名为“版本”的属性中。如果要删除一组窗口小部件,请将版本实体中的数字增加1,然后启动查询版本低于新版本号的所有窗口小部件。使用任何处理窗口小部件的查询,检查版本是否小于当前版本号,如果是,则从进程中丢弃(它被软删除)。您可以对其进行优化,以便查询不会返回大多数软删除的项目,也可以包含版本=当前过滤器。

答案 1 :(得分:0)

如果您在 后创建新的有缺陷的小部件 ,则删除操作已完成,为什么您希望它已被已执行的早期代码删除?

第2行的.fetch(keys_only=True)已经从数据存储中提取了现有密钥列表(此时新的缺陷实体不存在),因此下一行无法ndb.delete_multi()要知道你还没有.put()新的有缺陷的小部件。因此不会被删除。