【发布时间】:2014-03-18 16:13:48
【问题描述】:
我正在从事一个基于 GAE 的项目,该项目涉及大量用户群(可能有数百万用户)。我们使用 Datastore 来实现持久性。用户将通过用户名和电子邮件地址来识别,因此这两个属性在所有此类实体中应该是唯一的。因为 Datastore 不支持 ID 以外的唯一字段,所以我们需要事务来确保新用户注册时这些字段的唯一性。为了进行交易,用户实体需要包含在实体组中。
正如here 指出的那样,不建议使用大型实体组。因此,考虑到可能存储的大量用户,我正在考虑将它们放入多个较小的实体组中。每个组将有一个共同的父级,其 ID 由两个唯一字段(例如 MD5 总和的一部分)生成。插入新用户可能如下所示(在 Python 中):
@ndb.transactional
def register_new_user(login, email, full_name) :
# validation code omitted
user = User(login = login, email = email, full_name = full_name)
group_id = a_simple_hash(login, email)
group_key = ndb.Key('UserGroup', group_id)
query = User.query(ancestor = group_key).filter(ndb.OR(User.login = login, User.email = email))
if not query.get() :
user.put()
我看到此解决方案的一个问题是,仅通过 ID 获取用户是不可能的。我们必须使用完整的实体键。
这种方法还有其他缺点吗?有人试过类似的吗?
编辑
正如我在 cmets 中指出的那样,上述哈希值无法正常工作,因为它只会阻止注册具有非唯一电子邮件的用户以及与这些电子邮件匹配的非唯一用户名。如果哈希是基于单个字段计算的,它将起作用。
不过,我发现这种分片的概念本身很有趣,也许值得讨论。
【问题讨论】:
-
你听说过get_or_insert吗:developers.google.com/appengine/docs/python/ndb/…
-
是的,但是——据我所知——这种方法只能确保键名的唯一性。我不想使用用户名或电子邮件地址作为实体标识符。
-
您的代码只会阻止具有相同登录名和相同电子邮件的用户对。任何一个都可以重复!
-
@Greg 是的,同时我也想到了。我将编辑问题并指出这一点。
-
最终一致性并不意味着您“有机会在查询时找不到用户”。这意味着您可能无法在写入后几秒钟内检索您的实体。这里不需要交易。看我的回答
标签: google-app-engine google-cloud-datastore sharding ancestor