【问题标题】:How to import/sync data to App Engine datastore without excessive datastore reads or timeouts如何在没有过多数据存储读取或超时的情况下将数据导入/同步到 App Engine 数据存储
【发布时间】:2013-11-29 18:02:11
【问题描述】:

我正在编写一个使用远程 API 的应用程序,该 API 提供相当静态的数据(但仍然可以每天更新几次)。问题是 API 很慢,无论如何我更愿意将这些数据导入我自己的数据存储区,这样我也可以实际查询数据。

问题是结果包含大约 700 条记录,需要每 5 小时左右同步一次。这包括添加新记录、更新旧记录和删除旧记录。

我有一个可行的简单解决方案——但它像糖蜜一样慢,并且在超时之前使用了 30,000 次数据存储读取操作(在大约 500 条记录之后)。

最糟糕的是,这 700 条记录是针对单个客户的,而我这样做是为了测试。实际上,我希望为成百上千的具有相似记录数量的客户做同样的事情......你可以看到它是如何扩展的。

这是我的实体类定义:

class Group(ndb.Model):
    groupid = ndb.StringProperty(required=True)
    name = ndb.StringProperty(required=True)
    date_created = ndb.DateTimeProperty(required=True, auto_now_add=True)
    last_updated = ndb.DateTimeProperty(required=True, auto_now=True)

这是我的同步代码(Python):

    currentTime = datetime.now()
    groups = get_list_of_groups_from_api(clientid) #[{'groupname':'Group Name','id':'12341235'}, ...]

    for group in groups:
        groupid = group["id"]

        groupObj = Group.get_or_insert(groupid, groupid=group["id"], name=group["name"])
        groupObj.put()

    staleGroups = Group.query(Group.last_updated < currentTime)
    for staleGroup in staleGroups:
        staleGroup.delete()

【问题讨论】:

  • 您能否详细说明一下,为什么每个客户端大约需要 30,000 次读取?当只需要处理大约 700 个实体时。
  • 我不知道为什么它使用 30,000 次读取操作。这是我的问题的一部分。我更希望它尽可能少。我不是故意进行 30,000 次读取操作——这是我以某种方式实现的结果:/
  • 能否提供 get_list_of_groups_from_api() 代码?我怀疑你想修改它以返回更少的组......
  • 它所做的只是返回一个列表中约 700 个组项的列表(这看起来像我在该行末尾的评论)。该函数对数据存储没有任何作用——只是对 json 端点的简单 Web 请求。该函数只需要 5 秒即可返回。所以在超时之前剩余的 55 秒完全是由于函数调用下面的代码中的内容。
  • 你说的 remote api 是什么意思?针对远程 api `/_ah/remote_api' 运行的代码可以运行数天,因此您不会超时。

标签: python google-app-engine optimization google-cloud-datastore app-engine-ndb


【解决方案1】:

我无法告诉你为什么会获得 30,000 次读取操作。

您应该首先运行 appstats 并分析此代码,以查看正在执行数据存储操作的位置。

话虽如此,我可以在您的代码中看到一些真正的低效率。

例如,您的删除陈旧组代码效率极低。

您应该进行 keys_only 查询,然后进行批量删除。 你正在做的事情真的很慢,循环中的每个 delete() 都有很多延迟。

get_or_insert 也使用事务(如果组不存在,则 put 已经完成,然后您执行第二次 put()),如果您不需要事务,您会发现事情会运行得更快。您没有存储任何其他数据的事实意味着您可以盲目地写入组(所以初始获取/读取),除非您想保留 date_created

其他加快速度的方法是对键列表进行批量获取/放置。 然后对于所有不存在的实体,做一个批处理 put()

同样,这比遍历每个键要快得多。

另外你应该使用一个任务队列来运行这组代码,然后你有一个 10 分钟的处理窗口。

之后,可以通过将流程分成两个任务来实现进一步的扩展。第一个创建/更新组实体。完成后,您将启动删除陈旧组的任务 - 将日期时间作为参数传递给下一个任务。

如果您的实体数量超过了这个简单模型所能处理的数量,那么就开始研究 MapReduce。

但对于初学者来说,只需专注于使您当前运行的工作更有效率。

【讨论】:

    猜你喜欢
    • 2011-08-31
    • 2012-10-08
    • 1970-01-01
    • 2014-04-28
    • 2010-11-03
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多