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



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

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

其他有趣的说明:如果我允许任务队列在执行数据存储查询之前完全完成,然后执行数据存储查询,它将按预期运行,并且不会覆盖/丢弃任何内容。

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

您还需要注意,查询(如果它们不是祖先查询(最终是一致的,这意味着它们的结果有点"落后于"实际数据存储信息(从更新数据存储信息到查询使用的相应索引相应地更新需要一些时间(。因此,在处理查询结果中的实体时,还应以事务方式验证其内容。就个人而言,我更喜欢进行keys_only查询,然后通过密钥查找获取实体,这些查找始终是一致的(当然,如果我打算更新实体,并且在读取时(如果需要(,也是如此(。

例如,如果查询没有唯一 ID 的实体,则可能会获得实际上最近操作过且具有 ID 的实体。因此,您应该(事务性地(检查实体是否确实具有 ID 并跳过其更新。

此外,请确保未更新从投影查询获取的实体 - 从此类查询获得的结果可能无法代表整个实体,将它们写回将清除投影中未包含的属性。