更新大量 NDB 实体失败

Posted

技术标签:

【中文标题】更新大量 NDB 实体失败【英文标题】:Update for big count of NDB Entities fails 【发布时间】:2015-04-25 19:47:49 【问题描述】:

我的任务很简单。迁移并向现有 NDB 实体(约 100K 实体)添加新字段(重复和复合属性)后,我需要为其设置默认值。

我首先尝试了该代码:

q = dm.E.query(ancestor=dm.E.root_key)
for user in q.iter(batch_size=500):
     user.field1 = [dm.E2()]
     user.put()

但它会因此类错误而失败:

2015-04-25 20:41:44.792 /**** 500 599830ms 0kb AppEngine-Google; (+http://code.google.com/appengine) module=default version=1-17-0
W 2015-04-25 20:32:46.675 suspended generator run_to_queue(query.py:938) raised Timeout(The datastore operation timed out, or the data was temporarily unavailable.)
W 2015-04-25 20:32:46.676 suspended generator helper(context.py:876) raised Timeout(The datastore operation timed out, or the data was temporarily unavailable.)
E 2015-04-25 20:41:44.475 Traceback (most recent call last): File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 267, in

任务在单独的任务队列上运行,因此它至少有 10 分钟的时间来执行,但似乎还不够。奇怪的另一件事:来自 NDB 的警告。可能是因为来自其他实例(由用户发起)对相同实体的更新而导致死锁,但不确定。

无论如何,我想知道此类任务的最佳实践(也是最简单的)。我知道 MapReduce,但目前它让我觉得此类任务过于复杂。

更新:

我还尝试通过抓取数组中的所有实体来使用put_multi,但 GAE 会在实例超过约 600 MB 内存(限制为 500 MB)时立即停止该实例。似乎没有足够的内存来存储所有实体(~100K)。

【问题讨论】:

有趣,你试过put_multi()put_async() 看看是否有所改善? 请注意,Datastore 本身有一个截止日期 (default is 60 seconds)。我不知道 ndb 是否在幕后做任何聪明的事情来批量放置你的实体 - 如果你减少你的批量大小,或者将实体添加到列表中并一次性放入会发生什么(使用put_multi()? 已更新put_multi 信息 实体都在同一个组吗? @Skie,你不应该用put_multi() 为每个实体列出 500 个实体吗?不要put_multi()一次将所有100K记录放在一个列表中,将所有100K记录放在一个列表中肯定会超出内存限制。 【参考方案1】:

在您执行_migrate_users() 之后,它将处理 50 个用户,然后创建另一个任务来处理接下来的 50 个用户,依此类推。 根据实体的大小,您可以使用大于 50 的批量大小。

def _migrate_users(curs=None):
  users, next_curs, more = User.query().fetch_page(50, start_cursor=curs)
  for user in users:
    user.field1 = 'bla bla'
  ndb.put_multi(users)
  if more:
    deferred.defer(_migrate_users, next_curs, _queue='default')

【讨论】:

谢谢!光标对这项任务有很大帮助。此外,我还有其他任务可以向某些用户发送推送通知,我也会尝试在那里使用它。

以上是关于更新大量 NDB 实体失败的主要内容,如果未能解决你的问题,请参考以下文章

从数据存储区查询大量 ndb 实体的最佳实践

ndb.query.count() 失败,大型实体的查询截止日期为 60 秒

GAE ndb 存储大型一对多关系的最佳实践

EntityFramework 更新实体失败 - 无法跟踪

在 Google App Engine 上的数据存储区中更新大量实体

实体框架:添加迁移失败,无法更新数据库