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 データベースを使用しています。

4

1 に答える 1

4

このエラーは、postgisアダプターが ActiveRecord 接続プールからの古い/無効な接続を使用しようとしたために発生します。この問題に対処するには、次の 2 つの方法があります。

  1. スレッド/プロセスの数に一致するように接続プールのサイズを調整します
  2. 接続のリーピング頻度を下げる (Reaper は、N 秒ごとにプールで無効な接続をチェックします)

#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_FREQ5 秒に減らしてみてください。

于 2014-03-12T15:39:56.690 に答える