Heroku + Sidekiq:ActiveRecord :: StatementInvalid:PG :: UnableToSend:SSL SYSCALL错误:检测到EOF

时间:2013-11-06 01:11:30

标签: heroku connection-pooling rails-activerecord rails-postgresql heroku-postgres

您好我们正在与Unicorn和Sidekiq一起使用Heroku的Cedar堆栈。我们间歇性地得到以下错误

BurnThis ActiveRecord::StatementInvalid: PG::UnableToSend: SSL SYSCALL error: EOF detected

ActiveRecord::StatementInvalid: PG::ConnectionBad: PQconsumeInput() SSL SYSCALL error: Connection timed out

有没有人知道这些错误的直接原因是什么?与我们的数据库连接太多了吗?我们已经通过以下方式设置了分叉:

unicorn.rb

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 30
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::

Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  # other setup
  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['adapter'] = 'postgis'
    config['pool']              = ENV['DB_POOL'] || 5
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    ActiveRecord::Base.establish_connection(config)
  end
end

和sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq' }

  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['adapter'] = 'postgis'
    config['pool']              = ENV['DB_POOL'] || 5
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    ActiveRecord::Base.establish_connection(config)
  end
end

Sidekiq.configure_client do |config|
  config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq' }
end

我们的数据库池大小相当大DB_POOL = 100,我们在PG数据库上显然同时支持500个连接。

1 个答案:

答案 0 :(得分:4)

此错误是由您的postgis适配器尝试使用ActiveRecord连接池中的陈旧/无效连接引起的。有两种方法可以解决这个问题:

  1. 调整连接池的大小以匹配线程数/进程
  2. 降低连接收割频率(Reaper检查池是否有死连接,每N秒)
  3. 要实现#1,您需要设置适合Unicorn和Sidekiq的池大小,这可能有不同的需求。

    Unicorn是单线程的,因此每个进程的默认池大小5连接对您来说是正确的。这将为每个WEB_CONCURRENCY后端独角兽工作者分配最多5个连接。您应该重置默认池大小并使用现有的unicorn.rb

    $> heroku config:set DB_POOL=5
    
    然而,Sidekiq使用了一个非常不同的模型。默认情况下,Sidekiq有一个进程和N个线程。您需要比Sidekiq线程数稍大的DB池大小。您可以在config/initializers/sidekiq.rb中按如下方式实施此操作:

    Sidekiq.configure_server do |config|
      pool_size = Sidekiq.options[:concurrency] + 2
    
      config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq', :size => pool_size }
    
      if defined?(ActiveRecord::Base)
        config = Rails.application.config.database_configuration[Rails.env]
        config['adapter'] = 'postgis'
        config['pool']              = pool_size
        config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
        ActiveRecord::Base.establish_connection(config)
      end
    end
    

    我最好的猜测是,使用这么大的100连接池,你更有可能产生死连接。适当调整池的大小应该解决这个问题。

    如果这不起作用,您应该尝试将DB_REAP_FREQ减少到5秒。