【问题标题】:RnR: Long running query, Heroku timeouts: webhooks? Ajax?RnR:长时间运行的查询,Heroku 超时:webhooks?阿贾克斯?
【发布时间】:2012-11-07 14:43:39
【问题描述】:

问题来了,我们有一个用户想要显示的数据。查询,我们优化和索引的速度与我认为的一样快。我们可能会减少一两秒钟,但由于数据量很大,我们无能为力。

无论如何,因此查询在仅限于一两天的数据时运行良好,但是用户运行它一两个星期的数据。所以查询两三周的数据大约需要 40 秒,Heroku 超时 30 秒,这是行不通的。所以我们需要一个解决方案。

所以在这里和谷歌搜索,我看到 webhooks 或 Ajax 可以作为解决方案的 cmets。但是,我一直无法找到一个真实的具体例子。我还看到一条评论,有人说我们可以发送某种“重置时钟”的回复。但再次听起来很有趣,但找不到一个例子。

我们有点不知所措,用户不满意,所以我们需要一个快速简单的解决方案。在此先感谢您的帮助!

【问题讨论】:

  • 是否有无法对结果进行分页的原因?我最近一直在使用数据库,并且相当多的表有超过 300 万个包含复杂数据集和关联的结果。如果没有分页,那将是一场噩梦。如果您使用 mysql2 gem,您可能对“流”选项感兴趣:github.com/brianmario/mysql2#streaming。抱歉,我没有具体的例子。
  • 顺便说一句,如果这是在图表上显示数据,我可能会使用 AJAX 回调并批量获取数据,然后我会缓存该数据。我们需要更多关于如何使用这些数据的信息。
  • 流媒体真的很有趣。我想我可以在其他地方使用它。我们进行分页,问题在于实际查询执行时间约为 30-40 秒。超时时间为 30,在 Heroku 上无法调整。因此,执行查询所花费的时间比结果更重要。
  • 分页是否在查询级别使用限制/偏移完成?您一次要获取多少条记录,以及该数据集的表中有多少条记录?这些数据是用于图表/绘图还是平均结果?
  • 没有正在使用 Kaminari 完成分页。我做了一个快速测试,看看限制为 30 行是否会加快查询速度,它确实会加快查询速度,但只需大约一秒钟,我们需要保存大约 10 行以确保安全。

标签: ruby-on-rails ajax ruby-on-rails-3 webhooks


【解决方案1】:

我遇到了类似的问题。我的 Sinatra 应用程序中有一个本质上是“批量下载”页面,我的客户端应用程序调用该页面将数据导入浏览器中的本地 webSQL 数据库。

下载页面(我们称之为“GET /download”)查询 CouchDB 数据库以获取给定视图中的所有文档,而这部分过程(很像您的查询)需要很长时间。

我能够通过使用 Sinatra 的流 API 解决这个问题。如上所述,您可以通过在 30 秒时间结束之前在响应中发送至少一个 by 来“重置”Heroku 中的时钟。这会将时钟再重置 55 秒(并且您发送的每个额外字节都会再次重置时钟),因此当您仍在发送数据时,连接可以无限期地保持打开状态。

在 Sinatra 中,我可以替换它:

get '/download' do
  body = db.view 'data/all'
end

..用这样的东西:

get '/download' do
  # stream is a Sinatra helper that effectively does 'chunked transfer encoding'
  stream do |out|
    # Long query starts here
    db.view 'data/all' do |row|
      # As each row comes back from the db, stream it to the front-end
      out << row
    end
  end
end

这对我很有效,因为“第一个字节的时间”(即 db 查询返回第一行所用的时间远低于 30 秒的限制。

唯一的缺点是,之前我将所有结果从数据库返回到我的 Sinatra 应用程序,然后计算整个结果的 MD5 和以用作 etag 标头。我的客户端应用程序可以使用它来执行条件 HTTP 获取(即,如果它尝试再次下载并且没有修改任何数据,我可以发送 302 Not Modified);此外,它还可以与它自己接收到的数据的校验和进行比较(以确保它在传输过程中没有被损坏/修改)。

一旦您开始在响应中流式传输数据,您将无法计算要作为 HTTP 标头发送的内容的 MD5 总和(因为您还没有所有数据;而且您无法发送标头在您开始发送正文内容之后)。

我正在考虑将其更改为某种分页、多 AJAX 调用的解决方案;正如 Zenph 上面建议的那样。或者使用某种工作进程(例如 Resque、DelayedJob)将查询卸载到;但是我不确定当准备好获取数据时如何通知客户端。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2015-01-13
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 2018-07-04
    • 1970-01-01
    • 2014-07-01
    • 2011-05-23
    相关资源
    最近更新 更多