【问题标题】:Should I optimize around reads or CPU time in Google App Engine我应该在 Google App Engine 中围绕读取或 CPU 时间进行优化吗
【发布时间】:2012-09-18 20:29:54
【问题描述】:

我正在尝试优化我的设计,但很难正确看待事物。假设我有以下情况:

A.一个用户有 1,000 个状态更新。这些更新存储在单独的实体状态中。我想获得一个用户的状态,它在日期 X 之后有一个 uploadDate。所以我做了一个查询:

statuses = Statuses.query(Statuses.uploadDate > X).fetch()

B.一个用户有 1,000 个状态更新。每个用户实体都有一个列表属性list_of_status_keys,它是用户状态的所有键的列表。我想在日期 X 之后使用 uploadDate 获取所有状态。所以我很容易使用statuses = ndb.get_multi(list_of_status_keys) 获取状态列表。然后我遍历每一个,检查日期:

for a_status in statuses:
  if a_status.uploadDate > X:
     myList.append(a_status)

我真的不知道我应该优化哪个。查询看起来更有条理,但通过键获取更快。有人有什么见解吗?

更新

归结为: 在对 GAE 的每个 http 请求中,我都会收到用户的所有通知和状态更新(就像 facebook 一样)。使用 Appstats,它告诉我每个请求花费 490 微便士(其中 1 便士 = 1,000,000 微便士)。

获取通知和状态对用户来说很重要,因此您可以期望他们多次这样做。我很难确定这是否很多。我吓坏了,试图以任何可能的方式最小化这个数字。我以前从未运行过服务,所以我不知道这是否应该花费多少。这是数学:

当没有返回结果时,每个请求花费 490 微便士(因此仅对于基本查询,它花费 490,但在某些情况下,当返回多个结果时,它可能花费 10,000 mp),所以对于 1 便士,我可以运行 2040请求,或者 1 美元,我可以运行 204,000 个请求。

假设我有 50,000 个用户,每个用户每天检查 75 次通知(合理):

75 requests X 490 mp per request X 50,000 users = 1,837,500,000 micropennies per day = 1837.5 pennies = 18.37 dollars per day.(是吗?)

我以前从未运行过大规模服务,那么这些是通常的成本吗?还是这太高了?每个请求 490 小便士是否高?如果需要,我将如何找到答案?

【问题讨论】:

  • 那么,您更关心速度还是可读性?在第二种情况下,请注意循环也可以写成理解:[s for s in statuses if s.uploadDate > X]
  • @larsmans 可读性不是问题。我最关心的是成本,然后是速度,只要差异不大。
  • 说可读性不是问题可能会在以后导致代价高昂的问题:) 你所说的成本到底是什么意思? (不熟悉 GAE。)
  • @larsmans 但让我感到困惑的是,如果用户有 100,000 条状态更新,则查询只会获取并在内存中保存我需要的那些,超过日期 X。但是,如果没有查询,我会得到所有 100,000 个状态并在内存中过滤。我只是不确定它如何与 GAE 一起工作(或在任何系统上)。
  • @JoranBeasley 我想让我感到困惑的是......机器可以过滤内存中的 100,000 个项目吗?这是一项昂贵的手术,还是很正常?

标签: python algorithm google-app-engine


【解决方案1】:

设计 A 更胜一筹。

在设计中,GAE 将使用日期来执行键控查询。这意味着,Appengine 将自动为您在按日期排序的状态表上创建索引。由于它有一个索引,它只会读取和获取您指定日期之后的记录。这将为您节省大量读取。

在设计 B 中,您基本上必须自己完成索引工作。由于您需要获取每个状态,然后比较其日期,您将不得不做更多的工作,无论是在 CPU(即成本)方面还是在性能方面。

编辑

如果您的数据被如此频繁地访问,您可能还有其他设计选项。

首先,您可以考虑将 Status 对象组合到 StatusUpdatesPerDay 中。您每天创建一个实例,然后将状态更新附加到该对象。这会将数百次读取减少为几次读取。

其次,由于状态更新会被非常频繁地访问,所以可以将状态缓存在memcache中。这将降低成本和延迟。

第三,即使你没有像上面那样优化,我相信ndb已经内置了缓存。我从未使用过此功能,但您的实际读取计数可能低于您的计算。

第四个选项是避免一次显示所有状态更新。也许用户只想看到最后几个。然后,您可以在用户请求时(以及是否)使用查询游标来获取余数。

【讨论】:

  • 我明白你的意思。你能看看我的更新,看看你是怎么想的吗?
  • 如果用户会经常检查他们的状态,那么您还有其他设计选项。我会更新我的答案。
  • 所以收集所有状态的键并将它们放入 User 的数组属性中有点像手动索引,而这就是您所说的 Google App Engine 吗?
  • 所以我的目标不应该是最小化查询?
  • 不,你的目标不应该是最小化查询,你的目标应该是最小化数据库读取。获取的每个对象都将是数据库读取。使用查询还是自己获取都没有关系。因此,如果您通过键获取 所有 对象,然后只选择符合您条件的对象,那么您将比让 Appengine 为您使用一个查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
  • 1970-01-01
相关资源
最近更新 更多