ndb与一致性:为什么在没有父项的查询中会出现这种行为
我正在用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的简写。