【问题标题】:Google AppEngine - Big datastore readsGoogle AppEngine - 大数据存储读取
【发布时间】:2012-08-23 19:55:34
【问题描述】:

我需要读取 Google AppEngine 数据存储中的所有条目以进行一些初始化工作。有很多实体(目前为 80k),而且还在继续增长。我开始达到 30 秒的数据存储查询超时限制。

对于如何在数据存储区中对这些类型的大量读取进行分片,是否有任何最佳实践?有什么例子吗?

【问题讨论】:

  • 你能解释一下用例吗?
  • 我有一个查询,它基本上只是在我的数据存储中扫描特定类型的实体。那里大约有 80k 个,它们需要很长时间才能阅读,大约 45 秒。这超过了数据存储读取超时,这意味着这些表扫描失败。我试图了解如何以某种方式将我的读取分成小块,或者以其他方式将其推送到更长期限的处理类型,以便我的初始化不会失败。此外,我拥有的实体数量(今天为 80k)可能会增长,因此我希望这适用于 800k 实体。 @SebastianKreft
  • 听起来像是 mapreduce 的工作。
  • 在不知道更多关于数据是什么以及为什么要一次查询这么多数据的情况下,我所能做的就是同意@DanielRoseman 的观点,即 mapreduce 往往是解决此类工作的好工具尺寸。有了更多关于查询和数据背后的推理和目的的信息,我们或许能够提供更好的建议。

标签: google-app-engine google-cloud-datastore


【解决方案1】:

您可以通过多种方式解决此问题:

  1. Task Queue 上执行您的代码,它有 10 分钟的超时时间而不是 30 秒(实际上更像是 60 秒)。最简单的方法是通过DeferredTask

    警告:DeferredTask 必须是可序列化的,因此很难传递复杂的数据。也不要让它成为一个内部类。

  2. backends。后端实例服务的请求没有时间限制。

  3. 最后,如果您需要拆分一个大任务并并行执行,请查看mapreduce

【讨论】:

  • 感谢您的分析。我认为你基本上是对的。我的一个问题是关于任务截止日期。我对数据存储读取截止日期的理解仍然是 30 秒,无论是在任务中还是在常规 servlet/JSP 页面中。如果这是真的,有没有什么好的方法可以使用多个任务来分块读取?我正在考虑启动 10 个任务,每个任务都到达一个键的一部分。我知道这基本上是 MR 所做的,但只是想知道。
  • 是的,这就是我们正在做的。使用游标查询数据库并在每次迭代中收集 1000 个实体,然后创建一个 DeferredTask 并将数据传递给它。这没有问题:我们在几分钟内处理了 200 万个实体(2000 个任务)。
  • 但是您还应该重新考虑您的架构:在 NoSQL 中,最好在数据进入时实时计算,而不是像这样运行大型昂贵的查询。
  • 此外,数据存储截止日期仅适用于您进行过大的读取操作:例如进行读取并传递 1M 键。但对于小型读取,例如 1000 个实体,这不是问题。
【解决方案2】:

StackExchange 上的这个答案对我很有帮助:

Expired queries and appengine

我必须稍微修改一下才能为我工作:

def loop_over_objects_in_batches(batch_size, object_class, callback):

    num_els = object_class.count() 
    num_loops = num_els / batch_size
    remainder = num_els - num_loops * batch_size
    logging.info("Calling batched loop with batch_size: %d, num_els: %s, num_loops: %s, remainder: %s, object_class: %s, callback: %s," % (batch_size, num_els, num_loops, remainder, object_class, callback))    
    offset = 0
    while offset < num_loops * batch_size:
        logging.info("Processing batch (%d:%d)" % (offset, offset+batch_size))
        query = object_class[offset:offset + batch_size]
        for q in query:
            callback(q)

        offset = offset + batch_size

    if remainder:
        logging.info("Processing remainder batch (%d:%d)" % (offset, num_els))
        query = object_class[offset:num_els]
        for q in query:
            callback(q)

【讨论】:

    猜你喜欢
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多