Подтвердить что ты не робот

Heroku + Sidekiq: ActiveRecord:: StatementInvalid: PG:: UnableToSend: ошибка SSL SYSCALL: обнаружен EOF

Привет, мы бегаем по стеку Героку кедра с 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, и мы находимся в базе данных PG, которая, по-видимому, поддерживает 500 соединений одновременно.

4b9b3361

Ответ 1

Эта ошибка вызвана адаптером postgis, пытающимся использовать устаревшее/мертвое соединение из пула соединений ActiveRecord. Существует два способа решения этой проблемы:

  • Размер пула подключений в соответствии с количеством потоков/процессов
  • Более низкая частота получения соединения (Reaper проверяет пул для мертвых соединений, каждые N сек.)

Чтобы реализовать # 1, вам нужно установить размер пула, подходящий для Unicorn и для Sidekiq, у которых, вероятно, будут разные потребности.

Единорог однопоточный, поэтому размер пула по умолчанию 5 для каждого процесса правильный для вас. Это будет содержать до 5 подключений для каждого из WEB_CONCURRENCY бэкэнд-единорогов. Вы должны reset размер пула по умолчанию и использовать существующий unicorn.rb:

$> heroku config:set DB_POOL=5

Однако Sidekiq использует совсем другую модель. По умолчанию Sidekiq имеет один процесс и N потоков. Вы хотите немного больший размер пула БД, чем количество потоков Sidekiq. Вы можете реализовать это в своем 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 секунд.