Rails 4 数据库连接池错误

9

我有一个使用NGINX和Puma托管的Rails应用程序。大约每隔10小时,该应用程序就会变得无法使用。当用户尝试连接时,会显示以下错误消息:

Error during failsafe response: could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)

直到应用程序重新启动才会停止这种情况。
我阅读过,这是因为数据库连接池已满,因此在Rails应用程序中必须创建线程,但当它们完成后没有关闭与数据库的连接。 据我所知,只有一个地方在应用程序代码中使用线程:一个块使用Ruby Timeout模块,但它不访问数据库。
按照以下指南 https://devcenter.heroku.com/articles/concurrency-and-database-connections(实际上我没有使用Heroku),我已将数据库连接池的大小设置为5,并使用以下配置文件:
#config/initializers/database_connection.rb
Rails.application.config.after_initialize do
  ActiveRecord::Base.connection_pool.disconnect!

  ActiveSupport.on_load(:active_record) do
    config = ActiveRecord::Base.configurations[Rails.env] ||
                Rails.application.config.database_configuration[Rails.env]
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    config['pool']              = ENV['MAX_THREADS'] || 5 
    ActiveRecord::Base.establish_connection(config)
  end

结束

该网站使用Rails 4.0.0进行托管。我已经阅读过,这可能实际上是Rails 4.0.0的问题,而且这在后来的版本中已得到修复,但我不确定。

在Heroku上使用Postgres出现ConnectionTimeoutError
  1. 有没有办法监视连接池中活动数据库连接的数量?这将使调试更加容易。
  2. 在Rails应用程序代码中使用Timeout模块是否可能导致此问题?
  3. 这可能是Rails 4.0.0的问题,而不是我的应用程序的问题吗?

rails应用正在生产环境中运行。如果需要,我可以提供有关我的Puma、NGINX配置的更多信息。


我在一个4.1的应用程序中也看到了很多这样的问题,而在3.x上从未见过,因此我认为问题并没有真正得到解决。 - riffraff
有人找到解决方法了吗?我也遇到了这个问题。我有一种预感它与airbrake gem和/或在application_controller.rb中使用current_user有关。还有其他人使用airbrake gem或在application_controller.rb中使用current_user遇到此错误吗? - Catfish
通过将我的开发服务器切换到webrick,我没有看到这个错误。我认为罪魁祸首是puma。 - Catfish
2个回答

2
失败安全响应尝试分配数据库连接可能是一个重要线索。了解一下失败安全响应的具体情况可能会有所帮助。假设当原始请求触发异常时,失败安全响应被触发。调用failsafe响应的rails show_exception例程是在ConnectionManager为当前请求调用clear_active_connections!之后调用的(该请求由于异常而失败),这意味着rails将不会在failsafe响应失败后自动释放数据库连接。这意味着failsafe响应处理程序负责清理其自己的数据库连接。我不确定让failsafe响应处理程序尝试连接到数据库是否是一个良好的实践,但如果这是所需的行为,则您可能需要在failsafe处理程序结束时显式调用clear_active_connections!(在ensure块中)。
我一直在调查我自己应用程序中的类似问题,并发现这是一个关于连接工作的有用指南:https://bibwild.wordpress.com/2014/07/17/activerecord-concurrency-in-rails4-avoid-leaked-connections/。虽然其中引用的代码可能需要进行一些调整,但其中有一个很好的概述,介绍了如何检测何时创建隐式数据库连接。

0

我认为这不是Rails 4.0.0的问题。

正如Ruby超时模块文档中提到的,它会生成一个新线程。我认为有可能会生成长时间运行的线程,保持数据库连接处于活动状态。要检查正在运行的线程,您可以使用Thread.list方法。还要记住,您的池大小必须大于等于Puma线程乘以Puma工作进程数。


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