ndb与一致性:为什么在没有父项的查询中会出现这种行为

4 投票
1 回答
1973 浏览
提问于 2025-04-17 14:20

我正在用Python和ndb做一些工作,但有些地方我搞不懂。下面我会贴出一些案例和代码:

models.py

class Reference(ndb.Model):
  kind = ndb.StringProperty(required=True)
  created_at = ndb.DateTimeProperty(auto_now_add=True)
  some_id = ndb.StringProperty(indexed=True)
  data = ndb.JsonProperty(default={})

这些测试是在交互式控制台中运行的,并且使用了dev_appserver.py的--high_replication选项:

测试 1

from models import Reference
from google.appengine.ext import ndb
import random

some_id = str(random.randint(1, 100000000000000))
key_id = str(random.randint(1, 100000000000000))

Reference(id=key_id, some_id=some_id, kind='user').put()
print Reference.query(Reference.some_id == some_id, Reference.kind == 'user').get()

# output:
# >> None

为什么会这样????现在,让我们在打印之前加一个sleep(1):

测试 2

from models import Reference
from google.appengine.ext import ndb
import random
from time import sleep

some_id = str(random.randint(1, 100000000000000))
key_id = str(random.randint(1, 100000000000000))

Reference(id=key_id, some_id=some_id, kind='user').put()
sleep(1)
print Reference.query(Reference.some_id == some_id, Reference.kind == 'user').get()

# output:
# >> Reference(key=Key('Reference', '99579233467078'), createdAt=datetime.datetime(2013, 1, 31, 16, 24, 46, 383100), data={}, kind=u'user', some_id=u'25000975872388')

好吧,假设这是在模拟将文档传播到所有Google的表格的时间,我当然不会在我的代码里加sleep。现在,让我们去掉sleep,添加一个父级!

测试 3

from models import Reference
from google.appengine.ext import ndb
import random
from time import sleep

some_id = str(random.randint(1, 100000000000000))
key_id = str(random.randint(1, 100000000000000))

Reference(id='father', kind='father').put()

Reference(parent=ndb.Key(Reference, 'father'), id=key_id, some_id_id=some_id, kind='user').put()
print Reference.query(Reference.some_id == some_id, Reference.kind == 'user', ancestor=ndb.Key(Reference, 'father')).get()

# output:
# >> Reference(key=Key('Reference', '46174672092602'), createdAt=datetime.datetime(2013, 1, 31, 16, 24, 46, 383100), data={}, kind=u'user', some_id=u'55143106000841')

这真让人困惑!只要设置一个父级就能给我强一致性!为什么呢?如果这是为了提供强一致性,为什么在插入数据时,所有文档默认不都用同一个父级呢?也许我完全搞错了,可能有更好的方法。请,有人能指导我一下吗!

提前谢谢大家

1 个回答

8

祖先查询是在同一个实体组内进行的(所以它们物理上很接近),并且是强一致的。

在测试1中,由于HRD是分布式的,所以它可能看不到put()的结果,因为它是最终一致的。

在测试2中,HRD有足够的时间变得一致,所以你在查询中能看到这个实体。

在测试3中,你把它放在同一个实体组里,所以它是强一致的。

: 为什么不把所有东西都放在同一个实体组里?
: GAE不能把一个巨大的数据集分布到多个服务器上,除非有很多实体组(这样它们才能分散到很多不同的服务器上)。实体组应该尽可能大,但不要超过这个大小(G有时会举例说把用户的“消息”放在用户对象下)。另外,由于写入实体组中的某个成员会锁定整个组,所以你会面临写入速度的限制(如果我没记错的话,大约是每秒1次写入,Alfred有相关的讲座)。

: 我的get()没有获取到对象,这不是应该的吗?
: 不是的,只有通过键获取的get()是强一致的,你使用的query().get()其实只是LIMIT 1的简写。

撰写回答