0

我试图用python实现与ndb的强一致性。 而且看起来像我缺少一些东西,因为我的阅读表现得像他们不一致。Ndb强一致性和频繁写入

查询是:

links = Link.query(ancestor=lead_key).filter(Link.last_status == 
None).fetch(keys_only=True) 

if links: 
    do_action() 

的关键结构是:

Lead root (generic key) -> Lead -> Website (one per lead) -> Link 

我有使用TaskQueue中同时执行多任务,这个查询在每次任务结束时进行。有时我在更新last_status字段时收到“太多争用”异常,但我使用重试来处理它。它能破坏一致性吗?

预期的行为是当last_status等于None时没有链接而调用do_action()。实际行为不一致:有时do_action()被调用两次,有时根本不会调用。

回答

1

使用祖先密钥获得强一致性有一个限制:每个实体组的每秒更新次数限制为一次。解决此问题的一种方法是分割实体组。 Sharding Counters描述了该技术。这是一篇旧文章,但据我所知,建议仍然健全。

+0

感谢您的回答!如果我经常更新实体会发生什么情况? 'link.put()'需要更多时间,因为它等待一段时间来保持每秒写入1次的频率?或者它立即返回并且随后的祖先查询可能会返回过期的结果? – subcoder

+0

我的回忆是,如果你超过了费率限制,你会得到一个例外,但我不知道另一个确切的例外。不过,这是一个简单的尝试。正如Dan所说,这是你需要在部署的应用程序中测试的东西。 –

1

添加到戴夫的答案这是第一件事要检查。

有一件事没有很好的文档记录,可能有点令人惊讶的是,争用也可能由读取操作引起,而不仅仅是写入操作。

每当事务开始时,被访问的实体组(通过读或写操作,无所谓)都被标记为这样。 too much contention错误表示太多并行事务同时尝试访问同一个实体组。即使没有任何事务实际尝试写入,它也可能发生!

注:这个论点是不通过开发服务器仿真,它只能在GAE上部署的时候看到的,与真实数据存储!

什么可以添加到混乱是自动重新尝试的事务,这可能发生在实际的写入冲突或只是简单的访问争用。对于最终用户来说,这些重试可能会显示为某些代码路径的可疑重复执行 - 我怀疑这可能会解释您被调用两次的您的报告do_action()

通常当你遇到这样的问题时,你必须重新访问你的数据结构和/或你访问它们的方式(你的交易)。除了保持强一致性(可能相当昂贵)的解决方案之外,您可能还想重新检查一致性是否是必须的。在某些情况下,它只是因为看起来简化了一些东西而被作为一个整体要求添加的。根据我的经验,它不会:)

0

您的示例中没有任何内容确保您的代码只被调用一次。

目前,我将假设你的“do_action”函数对链接实体做了一些事情,特别是它设置了“last_status”属性。

如果您没有在事务内执行查询和写入链接实体,则可能有两个不同的请求(任务队列任务)从查询中返回结果,然后将其新值写入Link实体(最后写入覆盖前一个值)。

请记住,即使您确实使用了事务,在事务成功完成之前,您也不知道其他人是否尝试执行写操作。如果您尝试在数据存储的外部执行某些操作(例如,向外部系统发出http请求),这一点很重要,因为您可能会看到来自事务的http请求,这些请求最终会因并发修改异常而失败。