如何调试Rails连接池的使用?

时间:2016-04-11 17:08:06

标签: ruby-on-rails activerecord sidekiq rails-activejob

我遇到了Sidekiq工人的问题。

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

我正在遵循有关使用ActiveRecord::ConnectionTimeoutError和适当大型连接池的建议。

我想知道我是否在耗尽连接池。我正在从size中记录connections.lengthActiveRecord::Base.connection_pool,但它们保持不变的大小= 100 connections.length = 5.这表明这不是资源泄漏问题。< / p>

我的MySQL服务器配置为允许最多400个并发连接。

我的工作最终看起来像这样:

class MyJob < ActiveJob::Base
  queue_as :default    
  rescue_from StandardError do |exception|
    # clear connections on exception. Not sure if this is a good idea or not.
    ActiveRecord::Base.clear_active_connections!    
  end

  def perform()
    logger.info "size"
    logger.info ActiveRecord::Base.connection_pool.instance_eval { @size }
    logger.info  "connections"
    logger.info ActiveRecord::Base.connection_pool.instance_eval { @connections }.length

    # Ensure connections come from connection pool.
    ActiveRecord::Base.connection_pool.with_connection do |conn|
      # do stuff
    end
  end
end

这是诊断造成这种情况的正确方法,无论是资源匮乏还是泄漏?是否有其他技术可以解决为什么会发生这种情况?

2 个答案:

答案 0 :(得分:2)

在我看来,这个ActiveRecord::ConnectionTimeoutError只能出现在一个场景中 - 当那么多想要使用数据库连接的线程时,池已经耗尽,甚至等待免费连接没有帮助(从source code中学到的)。

在你的情况下,这很奇怪。您只使用25个工作线程,但池设置为100个连接,因此有足够的保留。我仍然怀疑你必须在某个地方产生线程。也许你在工作中做一些线程?也许你使用一个在你的工作中创建线程的gem?

无论如何,如果你能够重现异常,我建议抓住它并获取所有线程发生时的列表,如下所示:

begin
  # job stuff...      
rescue ActiveRecord::ConnectionTimeoutError
  puts "listing #{Thread.list.count} threads:"
  Thread.list.each_with_index do |t,i| 
    puts "---- thread #{i}: #{t.inspect}"
    puts t.backtrace.take(5)  
  end
end

我预计会有100个或更多线程,你应该看看它们在回溯中究竟是哪个。

答案 1 :(得分:0)

尝试ActiveRecord::ConnectionAdapters::ConnectionPool#stat

ActiveRecord::Base.connection_pool.stat 
# => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }

connection_adapters/abstract/connection_pool.rb开始,处于有效记录5.2.2.2.1。