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

Posted

技术标签:

【中文标题】如何调试 Rails 连接池的使用情况?【英文标题】:How to debug Rails connection pool usage? 【发布时间】:2016-08-01 23:40:47 【问题描述】:

我遇到了 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 工作线程? Pool定义为100,如connection_pool.size所示,25个worker。 【参考方案1】:

试试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.1 中。

【讨论】:

感谢您的回复。可悲的是,我无法再尝试这个了。【参考方案2】:

在我看来,ActiveRecord::ConnectionTimeoutError 只能在一种情况下发生 - 当有这么多线程想要使用 DB 连接时,池已用尽,甚至等待空闲连接也无济于事(从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 个或更多线程,您应该从回溯中看到它们究竟卡在哪里。

【讨论】:

非常感谢。我会试试的。我自己没有编写任何线程,但谁知道其他库在做什么! 你找到什么了吗? 没有。我减少了 sidekiq 工作人员的数量并且没有错误。这将被列入长期调查名单。感谢您的检查。

以上是关于如何调试 Rails 连接池的使用情况?的主要内容,如果未能解决你的问题,请参考以下文章

rails 数据库连接池的工作原理

如何查看连接池的使用情况

WebLogic中查看连接池的使用情况

关于Binder连接池的跨应用使用方法

设计一个可靠的连接池

关于SQLSERVER数据库连接池