sidekiq サーバー (遅延したタスクを実際に実行しているサーバー上で実行されているプロセス) は、デフォルトで最大 25 のスレッドにダイヤルして、そのキューから作業を処理します。これらの各スレッドは、タスクで必要な場合、ActiveRecord を介してプライマリ データベースへの接続を要求している可能性があります。
接続プールが 5 つの接続しかなく、25 のスレッドが接続しようとしている場合、5 秒後にプールから使用可能な接続を取得できない場合、スレッドは放棄され、接続タイムアウトが発生します。エラー。
Sidekiq サーバーのプール サイズを同時実行レベルに近い値に設定すると (-c
プロセスの開始時にフラグで設定)、データベースへの接続をさらに多く開くという犠牲を払って、この問題を軽減することができます。たとえば、Heroku で Postgres を使用している場合、プランによっては 20 に制限されているものもあれば、接続制限が 500 に制限されているものもあります ( source )。
Unicorn のようなマルチプロセス サーバー環境を実行している場合は、フォークされた各プロセスが行う接続数も監視する必要があります。ユニコーン プロセスが 4 つあり、デフォルトの接続プール サイズが 5 の場合、ユニコーン環境は常に 20 のライブ接続を持つことができます。詳細については、Heroku のドキュメントを参照してください。また、DB プールのサイズは、各 dyno が開いている接続数が多くなることを意味するのではなく、新しい接続が必要な場合に、最大でその数が作成されるまで作成されることに注意してください。
そうは言っても、ここに私がしていることがあります。
# config/initializers/unicorn.rb
if ENV['RACK_ENV'] == 'development'
worker_processes 1
listen "#{ENV['BOXEN_SOCKET_DIR']}/rails_app"
timeout 120
else
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 2)
timeout 29
end
# The timeout mechanism in Unicorn is an extreme solution that should be avoided whenever possible.
# It will help catch bugs in your application where and when your application forgets to use timeouts,
# but it is expensive as it kills and respawns a worker process.
# see http://unicorn.bogomips.org/Application_Timeouts.html
# Heroku recommends a timeout of 15 seconds. With a 15 second timeout, the master process will send a
# SIGKILL to the worker process if processing a request takes longer than 15 seconds. This will
# generate a H13 error code and you’ll see it in your logs. Note, this will not generate any stacktraces
# to assist in debugging. Using Rack::Timeout, we can get a stacktrace in the logs that can be used for
# future debugging, so we set that value to something less than this one
preload_app true # for new relic
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
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
end
after_fork do |server, worker|
Signal.trap 'TERM' do
puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to sent QUIT'
end
Rails.logger.info("Done forking unicorn processes")
#https://devcenter.heroku.com/articles/concurrency-and-database-connections
if defined?(ActiveRecord::Base)
db_pool_size = if ENV["DB_POOL"]
ENV["DB_POOL"]
else
ENV["WEB_CONCURRENCY"] || 2
end
config = Rails.application.config.database_configuration[Rails.env]
config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
config['pool'] = ENV['DB_POOL'] || 2
ActiveRecord::Base.establish_connection(config)
# Turning synchronous_commit off can be a useful alternative when performance is more important than exact certainty about the durability of a transaction
ActiveRecord::Base.connection.execute "update pg_settings set setting='off' where name = 'synchronous_commit';"
Rails.logger.info("Connection pool size for unicorn is now: #{ActiveRecord::Base.connection.pool.instance_variable_get('@size')}")
end
end
そしてsidekiqの場合:
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
sidekiq_pool = ENV['SIDEKIQ_DB_POOL'] || 20
if defined?(ActiveRecord::Base)
Rails.logger.debug("Setting custom connection pool size of #{sidekiq_pool} for Sidekiq Server")
db_config = Rails.application.config.database_configuration[Rails.env]
db_config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
cb_config['pool'] = sidekiq_pool
ActiveRecord::Base.establish_connection(db_config)
Rails.logger.info("Connection pool size for Sidekiq Server is now: #{ActiveRecord::Base.connection.pool.instance_variable_get('@size')}")
end
end
すべてがうまくいけば、プロセスを起動すると、ログに次のようなものが表示されます。
Setting custom connection pool size of 10 for Sidekiq Server
Connection pool size for Sidekiq Server is now: 20
Done forking unicorn processes
(1.4ms) update pg_settings set setting='off' where name = 'synchronous_commit';
Connection pool size for unicorn is now: 2
ソース: