【发布时间】:2014-04-22 05:39:41
【问题描述】:
我想要一些关于在 Google App Engine 中执行强一致性读/写的最佳方法的建议。
我的数据存储在这样的类中。
class UserGroupData(ndb.Model):
users_in_group = ndb.StringProperty(repeated=True)
data = ndb.StringProperty(repeated=True)
我想为此数据编写一个安全的更新方法。据我了解,我需要在这里避免最终一致的读取,因为它们有数据丢失的风险。例如,下面的代码是不安全的,因为它使用了一个最终一致的普通查询:
def update_data(user_id, additional_data):
entity = UserGroupData.query(UserGroupData.users_in_group==user_id).get()
entity.data.append(additional_data)
entity.put()
如果查询返回的实体是陈旧的,数据就会丢失。
为了实现强一致性,我似乎有几个不同的选择。我想知道哪个选项最好:
选项 1:
使用get_by_id(),它始终是强一致的。但是,这里似乎没有一种巧妙的方法来做到这一点。没有直接从user_id 派生UserGroupData 的密钥的干净方法,因为关系是多对一的。要求我的外部客户端存储和发送 UserGroupData 的密钥似乎也有点脆弱和冒险。
选项 2: 将我的实体放在祖先组中,然后执行祖先查询。比如:
def update_data(user_id, additional_data):
entity = UserGroupData.query(UserGroupData.users_in_group==user_id,
ancestor=ancestor_for_all_ugd_entities()).get()
entity.data.append(additional_data)
entity.put()
我认为这应该可行,但是将所有 UserGroupData 实体放入一个祖先组似乎是一件极端的事情。它导致写入被限制为 ~1/秒。这似乎是错误的方法,因为每个UserGroupData 实际上在逻辑上是独立的。
我真正想做的是对根实体执行高度一致的查询。有没有办法做到这一点?我注意到一个建议in another answer 基本上对祖先组进行分片。这是可以做到的最好的吗?
选项 3:
第三种选择是执行keys_only 查询,后跟get_by_id(),如下所示:
def update_data(user_id, additional_data):
entity_key = UserGroupData.query(UserGroupData.users_in_group==user_id,
).get(keys_only=True)
entity = entity_key.get()
entity.data.append(additional_data)
entity.put()
据我所知,这种方法不会丢失数据,因为我的密钥没有改变,get() 给出了非常一致的结果。但是,我还没有看到任何地方提到过这种方法。这是合理的做法吗?我需要了解它有什么缺点吗?
【问题讨论】:
-
如果索引尚未使用新实体或删除的实体更新,则选项 3 仍可能丢失数据。您获得的键将是一致的,但索引可能不会。
标签: python google-app-engine google-cloud-datastore