我该如何降低Google App Engine数据存储的延迟?

13

通过appstats,我可以看到我的数据存储查询需要大约125毫秒(包括API和CPU),但是通常在执行查询之前会出现长时间的延迟(例如高达12000毫秒)。

我可以看到我的数据存储从数据存储中获取的延迟与我的查询无关(例如,相同的查询/数据具有非常不同的延迟),因此我认为这是一个应用程序引擎的调度问题。

其他人是否遇到了同样的问题?

有没有办法减少延迟(例如管理控制台设置)?

这是来自appstats的屏幕截图。此servlet几乎没有CPU处理。它使用getObjectByID然后执行数据存储查询。查询具有OR运算符,因此它被应用程序引擎转换为3个查询。

appstats截图 正如您所看到的,在第一个getObjectByID执行之前需要6000ms。在get操作之前没有任何处理(除了获取pm)。我认为这6000ms的延迟可能是由于实例预热造成的,因此我将空闲实例增加到2个以防止任何预热。

然后在getObjectByID和query之间有大约1000ms的第二个延迟。在get和query之间没有代码行。代码仅使用getObjectByID的结果,并将数据用作查询的一部分。

总计为8097ms,但是我的数据存储操作(以及99.99%的servlet)仅为514ms(45ms API),尽管每次运行servlet时这些数字都会发生变化。以下是对相同数据运行相同servlet的另一个appstats截图。 enter image description here

这是我的Java代码基础知识。出于安全原因,我不得不删除一些细节。

user = pm.getObjectById(User.class, userKey);           
//build queryBuilder.append(...
final Query query = pm.newQuery(UserAccount.class,queryBuilder.toString());
query.setOrdering("rating descending");
query.executeWithArray(args); 

编辑: 使用Pingdom,我可以看到GAE的延迟时间从450毫秒变化到7,399毫秒,相差1644%!! 这是在两个空闲实例和网站上没有用户的情况下。 enter image description here


你的问题听起来有些奇怪。Appstats没有显示任何在执行查询时的调度延迟。你能否包含一个Appstats页面的图像来看看你所说的是什么? - dragonx
是的,这很奇怪。我已经更新了问题,并附上了一个appstat图像和更多细节。感谢任何帮助。 - chow
你能发布正在执行的相关代码吗? - Sologoub
好的,已经将代码添加到问题中。 - chow
考虑到您并不总是遇到延迟,我怀疑您的代码不是主要问题(这并不意味着它不能最终进行优化,但我怀疑通过更改您的代码来解决问题)。我的猜测是您正在经历预热延迟,正如您所提出的。请参阅我的答案,其中分享了我在类似问题上的经验。 - JohnIdol
2个回答

9
我注意到我的一些应用程序中有非常相似的延迟(在7000-10000ms范围内)。我认为问题的主要部分(那6000ms)不在你的代码中。
根据我的观察,这个问题与AppEngine启动一个新实例有关。设置最小空闲实例可能有助于缓解,但它并不能解决它(我尝试了最多2个空闲实例),因为基本上即使你有N个空闲实例,app engine也会更喜欢旋转动态实例,即使只有一个请求进来,而会“保存”空闲实例以防止疯狂的流量飙升。这是高度反直觉的,因为你期望它使用已经存在的实例,并为将来的请求旋转动态实例。
总之,在我的经验中,除了任何非零数量的负载之外,这个问题(10000ms延迟)很少发生,许多人不得不恢复到每隔几分钟进行某种ping操作(可能是cron作业),以保持动态实例继续为用户提供服务,即使没有其他人在网站上。这种ping操作并不理想,因为它会耗尽你的免费配额(每5分钟ping一次会耗费超过一半的配额),但我真的还没有找到更好的替代方案。
总之,一般情况下,我发现当网站承受负载时,app engine非常棒,但是当你只有很少的(1-3)用户时,它并不出色。

1
谢谢你的回答。很有道理。我会尝试ping的想法。 - chow

1

Appstats 只有在您进行 GAE API/RPC 调用时才能帮助诊断性能问题。

在您的图表中,“空白”时间是在实例上运行代码所花费的时间。这不会是调度时间。

您猜测初始延迟可能是由于实例预热,这是非常有可能的。可能是执行框架代码。 我无法猜测 Get 和 Query 之间的延迟。可能是没有代码行,但您在 Query 中调用了一些需要处理时间的函数。

如果没有语言、框架或实际代码的知识,没有人能够帮助您。

为了诊断此问题,您需要自己添加某种性能跟踪。最简单(但不是高度准确)的方法是在代码执行时添加计时器并记录计时器值。


谢谢您的反馈。我已经添加了代码。这是一个非常简单的Java Servlet,使用JDO访问数据存储库。它没有使用任何框架。在我的应用程序的其他部分,我正在使用GWT,但如果它影响了这个Servlet,我会感到惊讶。 - chow
我还应该指出,同一servlet和数据请求并不总是有长时间的延迟。我附上了另一个运行快速的appstats截图。 - chow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接