Google app engine 提高大数据下ndb查询的吞吐量

Google app engine 提高大数据下ndb查询的吞吐量,google-app-engine,google-cloud-datastore,Google App Engine,Google Cloud Datastore,我试图在GAE应用程序中对存储在数据存储中的数据执行一些数据处理。瓶颈点是查询返回实体的吞吐量,我想知道如何提高查询的性能 我通常做的是: 所有工作都在任务队列中进行,因此我们有充足的时间(10分钟的截止时间) 我在ndb实体上运行查询,以选择需要处理的实体 当查询返回结果时,我将实体分组成批(比如1000个),并将它们发送到另一个任务队列进行进一步处理 存储的数据将会很大(比如500K-1M实体),10分钟的截止时间可能还不够。因此,当任务到达taskqueue截止日期时,我生成一个新任务。

我试图在GAE应用程序中对存储在数据存储中的数据执行一些数据处理。瓶颈点是查询返回实体的吞吐量,我想知道如何提高查询的性能

我通常做的是:

  • 所有工作都在任务队列中进行,因此我们有充足的时间(10分钟的截止时间)
  • 我在ndb实体上运行查询,以选择需要处理的实体
  • 当查询返回结果时,我将实体分组成批(比如1000个),并将它们发送到另一个任务队列进行进一步处理
  • 存储的数据将会很大(比如500K-1M实体),10分钟的截止时间可能还不够。因此,当任务到达taskqueue截止日期时,我生成一个新任务。这意味着我需要一个ndb.Cursor,以便从停止的位置继续查询
问题是查询返回实体的速率。我尝试了几种方法,并观察到以下性能(对我的应用程序来说太慢):

在while循环中使用fetch\u page()。

代码很简单

while has_more and theres_more_time:
 entities, cursor, more = query.fetch_page(1000, ...)
 send_to_process_queue(entities)
 has_more = more and cursor
使用这种方法,处理10K实体需要25-30秒。粗略地说,这是每分钟2万个实体。我尝试更改页面大小或前端实例的类;两人的表现都没有什么不同

分割数据并并行启动多个获取页面\u async()。

总体性能与上述相同。我尝试使用不同数量的段(从2到10),以便有2-10个并行fetch_async()调用。在所有情况下,总时间保持不变。调用的并行fetch_page_async()越多,完成每个页面所需的时间就越长。我还尝试了20次并行抓取,结果变得更糟。更改页面大小或前置实例类也没有影响

通过一个Fetch()调用获取所有内容。

现在,这是最不合适的方法(如果不是完全不合适的话),因为实例可能会耗尽内存,而且我没有得到一个光标,以防我需要生成另一个任务(事实上,我甚至没有能力这样做,该任务只会超过最后期限)。出于好奇,我试了一下,看看它的性能如何,我观察到了最好的性能!10K实体需要8-10秒,大约为每分钟60K实体。现在,这大约比fetch_page()快3倍。我想知道为什么会这样

在单个循环中使用query.iter()

这与第一种方法类似。这将利用查询迭代器的底层生成器,并且我可以从迭代器中获得一个游标,以防我需要生成一个新任务,因此它适合我。使用查询迭代器,它在16-18秒内获取了10K个实体,约为每分钟36-40K个实体。迭代器比fetch_页面快30%,但比fetch()慢得多

对于上述所有方法,我尝试了F1和F4前端实例,但数据存储性能没有任何差异。我还尝试更改查询中的batch_size参数,但仍然没有任何更改

第一个问题是,为什么fetch()、fetch_page()和iter()的行为如此不同,以及如何使fetch_page()或iter()与fetch()一样好?然后另一个关键问题是这些吞吐量(每分钟20-60K个实体,取决于api调用)是否是我们在GAE中所能做到的最佳吞吐量

我知道MapReduceAPI,但我认为它不适合我。顺便说一句,MapReduceAPI不支持查询,我也不想扫描所有的数据存储实体(这样做成本太高,速度太慢,查询可能只返回几个结果)。最后,但并非最不重要的是,我必须坚持GAE。求助于其他平台不是我的选择。因此,真正的问题是如何优化ndb查询

有什么建议吗?

新的实验功能(MapReduce的AppEngine API)可能很合适。它使用自动切分来执行多个并行工作进程,这可能有帮助,也可能没有帮助(如另一个链接问题中的方法C)。

您关于“无需扫描所有实体”的评论引发了一种想法,即自定义索引可以帮助您的查询。这可能需要更改模式,以不太正常的形式存储数据


从输出的角度设计一个解决方案-最简单的查询是什么产生了所需的结果,支持这种查询的实体结构是什么,从当前数据创建和维护这种实体结构需要做什么工作。

如果有人感兴趣,通过重新设计组件,我能够显著提高数据处理的吞吐量——有人建议我更改数据模型,但这是不可能的

首先,我对数据进行分段,然后在单独的taskqueue.Task中处理每个数据段,而不是从单个任务调用多个fetch_page_async(如我在第一篇文章中所述)。最初,GAE仅使用单个Fx实例按顺序处理这些任务。为了实现任务的并行化,我将组件移动到一个特定的GAE模块,并使用基本的扩展,即可寻址Bx实例。当我将每个数据段的任务排队时,我通过指定“target”选项明确指示哪个基本实例将处理每个任务

通过这种设计,我能够使用5个B4实例在4-5秒内(而不是40'-60'!)处理总共20000个实体


现在,由于Bx实例,这会带来额外的成本。我们必须微调我们需要的基本实例的类型和数量。

对于您的处理,我看不出使用fetch\u页面的任何真正原因,只需使用fetch和一个限制和一个光标,您不需要后退,也不需要知道它们是否正确