Heroku - ActiveRecord::ConnectionTimeoutError(在5.000秒内无法获得数据库连接(等待了5.000秒))

3

我有一个非常简单的应用程序,在本地运行没有问题,但是当部署到Heroku后,它很快就会停止工作,并出现500错误和以下日志中的错误:

ActiveRecord::ConnectionTimeoutError (could not obtain a database connection within 5.000 seconds (waited 5.003 seconds))

我已经搜索并找到了这个问题,它看起来非常相似。但我不太明白那个问题中对jpeg文件请求的相关性,也不理解答案中的问题所在。我可以通过重新启动服务器并多次调用返回404的页面来重现该问题。
我得到了与该问题中提到的相同结果(特别是Connections < DB_POOL):
 (staging) $ heroku pg:info --remote staging
=== HEROKU_POSTGRESQL_ONYX_URL (DATABASE_URL)
Plan:        Hobby-dev
Status:      Available
Connections: 5
PG Version:  9.3.4
Created:     2014-05-02 08:57 UTC
Data Size:   9.9 MB
Tables:      11
Rows:        6508/10000 (In compliance)
Fork/Follow: Unsupported
Rollback:    Unsupported

(staging) $ heroku config
.....
DB_POOL:                    10
.....

我根据railscast开发了我的解决方案,这似乎与其他问题中的方法相同。然而,我不理解提供在另一个问题中提供的答案以及它如何适用于我的解决方案,如下所示: routes.rb:
match ':status', to: 'errors#show', constraints: {status: /\d{3}/ }, via: :all

application.rb:

config.exceptions_app = self.routes

errorscontroller.rb

class ErrorsController < ApplicationController

    def show
        status = request.path[1..-1]
        case status
        when "404"
            @error = "404 - The page you were looking for cannot be found"
        when "403"
            @error = "403 - The page you were looking for is not accessible"
        when "500"
            @error = "500 - An error occurred within the server"
        end


        respond_to do |format|
            format.html { render action: "error" }
            format.json { render json: {status: status, error: @exception.message} }
        end
    end
end

error.html.erb

<div class='container'>
    <h1 class="errorh1">Oops something went wrong!!</h1>
    <h2 class="errorh2"><%= @error %></h2>
    <br>
    <p>We are sorry. Please <a href='#' data-uv-trigger="contact
">let us know</a> what you were trying to do so that we can look into the problem.</p>
    <br>
    <p>When you are ready to continue, <a href="/">go home</a> to start again.</p>
</div>

注意:我正在运行Rails 4.0.4(并在本地使用psql(PostgreSQL)9.3.4)

另一篇文章说,一个页面试图加载一个错误控制器的respond_to无法处理的MIME类型。这导致堆栈锁定。你的代码与他的破损代码类似,只处理.html.json。他通过添加例如format.all { render nothing: true, status: 422 }来修复它。你可以尝试一下。同时,你的error.html.?视图代码也会很有帮助。 - Gene
谢谢@Gene。我在format.json下面添加了format.all...。我会将error.html.erb添加到问题中。 - Richbits
添加 format.all 没有解决问题。 - Richbits
好的。这意味着链接的相似问题实际上是一个不同的问题。 - Gene
@Richbits,你能执行 heroku run rake db:migrate 吗? - Sachin Singh
2个回答

2

我认为你的ErrorsController没有问题,无论你是使用默认的还是放置它在其他位置,这个问题都会存在。

ActiveRecord::ConnectionTimeoutError简单地意味着数据库占用了所有连接,不能再接受任何连接请求。

可能出现这种情况的原因有几种。你可能在某些action中执行了耗时的query transaction操作。或者你可能使用了多线程服务器,如puma,或者多进程服务器,如unicorn(并且你错过了必要的配置)。也有可能出现dead connection,它会占用资源但不失效(就像deadlock一样)。

除非你想将数据库升级到非常大的计划,否则没有一个关键解决方案可以解决这个问题。

我建议你添加https://github.com/heroku/rack-timeout,这样每当请求需要很长时间才能响应(内部数据库),它就会引发Racke::Timeout异常。你可以rescue这个exception,也可以让它继续发生。如果你想知道发生了什么以及为什么会发生,newrelicairbrake可能会有所帮助。

最后一件事,在大型应用程序中,公共面向用户的app/site也会发生很多耗时的sql transactions,但它们会将所有这些事情缓存起来。如果你不介意复杂性,你也可以使用redismemcache

最后一点,如果你找不到解决方案,我建议你务必联系heroku support。他们非常乐于帮助。


1
我并不认为升级计划会有所帮助,因为在给出的示例中未超过DB_POOL值。我想我将不得不求助于Heroku支持,并且如果我得到解决方案,我会在这里更新。 - Richbits

-1
在您的数据库配置中增加池参数。

谢谢,但我理解如果DB_POOL > connections,则增加连接数不会有任何影响。这是一个无效的理解吗? - Richbits
你读过这个吗?https://devcenter.heroku.com/articles/concurrency-and-database-connections - Alex Tatarnikov
还有可能是Rails的问题,但在4.0.4版本中应该已经修复了。您可以在这里阅读更多信息:https://dev59.com/z3vaa4cB1Zd3GeqPA0Lz - Alex Tatarnikov
谢谢,我已经看了这两篇文章,但是对于描述的底层细节有一些困难。第一篇文章似乎针对多线程和多进程服务器采用不同的方法。Webbrick属于哪个阵营? - Richbits
1
@Richbits 在设置了 DB_POOL 之后,你是否重新启动了 Heroku? 你可以使用命令 heroku restart 来重启 Heroku。 - Sachin Singh
@SachinSingh 是的,我已经重新启动了,这似乎是唯一解锁的方法。 - Richbits

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