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

18

嗨,我们正在使用Heroku的Cedar堆栈,并配备Unicorn和Sidekiq。我们偶尔会出现以下错误:

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,而且我们使用的是一个支持500个并发连接的PG数据库。


1
请问,您是否拥有其中一个具有“高可用性”的Postgres计划?如此所示,https://addons.heroku.com/heroku-postgresql#premium-yanari - Patrick
在执行重启数据库的操作后,我曾经看到过这种类型的应用程序错误。重新启动应用程序服务器后,由于连接被重新建立,错误消失了。您是否发现在运行迁移或其他数据库活动时看到错误之间存在任何相关性? - srt32
你在Unicorn的配置中为什么要在after_fork块中设置config呢?似乎应该放在这两个块之外。 - slant
我得到了类似的错误信息:ActiveRecord::StatementInvalid (PG::UnableToSend: SSL连接意外关闭) - Chloe
1个回答

4
这个错误是由于你的postgis适配器试图使用来自ActiveRecord连接池的陈旧/失效连接引起的。有两种方法可以解决这个问题:
  1. 将连接池大小调整为与线程/进程数量匹配
  2. 降低连接清除频率(Reaper每N秒检查一次池中是否有死连接)
要实现第一种方法,您需要设置适合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秒。


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