如何调试Rails连接池使用?

14

我正在遇到Sidekiq工作者方面的问题。

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

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

我想找出是否用尽了连接池。我记录了ActiveRecord :: Base.connection_pool中的sizeconnections.length,但它们保持不变,大小为100,连接数为5,这表明这不是资源泄漏问题。

我的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

这是诊断导致资源匮乏或泄漏的正确方法吗?还有其他技术可以用来找出为什么会发生这种情况吗?


你的 database.yml 中定义的连接池大小是多少?你使用了多少个 Sidekiq 工作线程? - Matouš Borák
连接池被定义为100,如connection_pool.size所示,有25个工作线程。 - Joe
2个回答

13
尝试使用 ActiveRecord::ConnectionAdapters::ConnectionPool#stat
ActiveRecord::Base.connection_pool.stat 
# => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }

来自于 activerecord 5.2.2.1 中的 connection_adapters/abstract/connection_pool.rb


感谢您的回复。不幸的是,我不再有机会尝试这个了。 - Joe

7
ActiveRecord::ConnectionTimeoutError 错误只会出现在这种情况下——当有太多线程想要使用数据库连接时,连接池被耗尽,即使等待空闲连接也无济于事(从源代码了解)。

在你的情况下,很奇怪。你只使用了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个或更多的线程,您应该从回溯中准确地看到它们被卡在哪里。

太棒了,谢谢。我会尝试的。虽然我自己没有启动任何线程,但谁知道其他库在做什么! - Joe
你找到什么了吗? - Matouš Borák
1
没有问题。我减少了Sidekiq工作进程的数量,现在没有错误了。这个问题将被列入长期调查清单。感谢您的检查。 - Joe

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