数据存储区查询期间的 GAE 推送队列数据库争用

GAE Push Queue database contention during datastore query

总结 我有一个问题,我的任务队列中的数据库 writes(大约 60 个任务,速度为 10/s)在并发数据库 read 期间以某种方式 overwritten/discarded 相同的数据。我将解释它是如何工作的。任务队列中的每个任务都会为模型的特定数据存储实体分配一个唯一的 ID。 如果我 运行 对模型进行索引数据存储查询并在任务队列进行时循环遍历实体,我希望某些实体将由任务队列操作(即..分配了一个ID) 和其他尚未生效。不幸的是,在查询循环期间,似乎正在发生的事情是,已经被操作过的实体(即..成功分配了一个 ID)被覆盖或丢弃,说它们从未被操作过,即使 - 根据我的日志- 他们接受了手术。

为什么会这样?我需要能够在不影响后台任务队列写入操作的情况下读取数据的状态。我认为这可能是一个缓存问题,所以我尝试在查询中强制执行 use_cache=False 和 use_memcache=False,但这并没有解决问题。任何帮助,将不胜感激。

其他有趣的笔记: 如果我允许任务队列在 执行数据存储查询之前完全完成,然后执行数据存储查询,它会按预期运行并且没有任何 overwritten/discarded。

这通常表示对实体的写入操作未在事务中执行。事务可以检测此类并发写入(和读取!)操作并重试,确保数据保持一致。

您还需要注意查询(如果它们不是祖先查询)最终是一致的,这意味着它们的结果有点 "behind" 实际的数据存储信息(从数据存储开始需要一些时间信息被更新,直到查询使用的相应索引被相应地更新)。因此,在处理查询结果中的实体时,您还应该事务性地验证它们的内容。就我个人而言,我更喜欢制作 keys_only queries 然后通过键查找获取实体,这始终是一致的(当然,如果我打算更新实体,并且在读取时,如果需要,也在交易中)。

例如,如果您查询没有唯一 ID 的实体,您可能会得到实际上最近操作过并具有 ID 的实体。所以你应该(事务性地)检查实体是否真的有一个 ID 并跳过它的更新。

还要确保您没有更新从 projection queries 获得的实体 - 从此类查询获得的结果可能不代表整个实体,将它们写回会清除投影中未包含的属性。