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 соединений одновременно.
Ответы
Ответ 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 секунд.