フォークされた環境での Postgres 接続の適切な確立
この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。
最終更新日 2022年11月21日(月)
Table of Contents
呼び出しのたびに接続の再確立が必要になるというパフォーマンスへの影響を軽減するために、設計上、Postgres データベースへの接続は永続的です。これにより、アプリケーションのパフォーマンスは向上しますが、特にフォークされた環境では、接続の適切な確立も必要です。
フォークされた環境
フォークされたプロセスを使用するフレームワークまたはライブラリを使用している場合、Postgres (および、その他のすべてのリソース) への接続はフォークの完了後に確立する必要があります。これにより、フォークされた各プロセスに独自の接続が確実に割り当てられるようになり、no connection to the server
、SSL SYSCALL error: EOF detected
、SSL error: decryption failed or bad record mac
などの最も一般的な接続エラーのいくつかが回避されます。
ここには、いくつかの一般的なフレームワークやライブラリの接続手順が含まれています。
データベース接続プール
フォークベースのサーバーを使用している場合は、その種類にかかわらず、各フォークが独自のデータベース接続プールを受け取ります。このため、フォークベースの Web サーバーを使用しているほとんどのアプリケーションは、アプリケーションレベル (Rails、Sequel、Django など) の接続プールが使用されていない場合、または 1 のプールサイズで使用されている場合に最高のパフォーマンスが得られます。
データベース接続を過度に使用すると、全体的なパフォーマンスの低下、データベースサーバーにより報告される “メモリ不足” エラー、データベースサーバーによる追加クライアントからの接続の受け取りの拒否 (接続制限に到達) が発生する可能性があります。
このアドバイスから除外されるアプリケーションは、1 つの HTTP リクエストのコンテキスト内での複数の同時トランザクションを利用するか、またはそれを必要とするように意図的に記述されている傾向があります。
Ruby on Rails
Postgres の再接続に関する重要なバグが ActiveRecord で修正されています。 3.2.9. 以前のリリース (3.1、3.0、2.x) にはこの機能強化が適用されていません。ActiveRecord 3.2 を使用している場合は、バージョン 3.2.9 以降にアップグレードすることをお勧めします。
以前のバージョンでは、Heroku が自動的に クラッシュした dyno を再起動する ため、アプリケーションから PGError
が伝播されたらプロセスを終了することをお勧めします。
Unicorn サーバー
Unicorn は、フォークされたプロセスを使用して受信リクエストを処理する Rack HTTP サーバーです。unicorn.conf
設定ファイル で前と後のフォーク動作を指定します。
Rails アプリまたは ActiveRecord
を使用しているアプリでは、unicorn.conf
に次の before_fork
および after_fork
ブロックを追加します。
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 sent QUIT'
end
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection(
Rails.application.config.database_configuration[Rails.env]
)
end
Resque Ruby のキューイング
Resque は、フォーキングを使用して新しいワーカープロセスを作成します。メインプロセスの接続が (不必要なリソースの消費を回避するために) フォーキングの前に切断する必要があるのに対して、ワーカーの接続は フォークが発生した後に 確立する必要がります。
この動作は、イニシャライザで接続をクリーンアップして再確立することによって指定できます。
Resque.before_fork do
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
Resque.after_fork do
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
Sidekiq
Sidekiq は、スレッドを使用して、多くのジョブを同じプロセスで一度に処理します。接続の共有を防止するには、独自の接続を適切に確立するように Sidekiq サーバーを設定する必要があります。
この動作は、Sidekiq イニシャライザで接続をクリーンアップして再確立することによって指定できます。
バックグラウンドワーカーの並列性とデータベース接続を参照してください。
New Relic EXPLAIN の無効化
New Relic の自動 EXPLAIN
の現在の実装によって、フォークごとに 1 つの余分なデータベース接続が使用される可能性があります。余分な接続を許容できない大容量のアプリケーションの場合は、New Relic の自動 EXPLAIN
機能を無効にするだけの価値があります。この実行方法に関する手順については、New Relic のドキュメントの「Manually changing your configuration」(手動での設定変更) を参照してください。
別の方法として、Postgres 9.2 以降を使用している場合は、pg_stat_statements の使用を検討してください。それ自体で有効なだけでなく、New Relic の自動 EXPLAIN
を無効にすることによって発生する可視性の損失の軽減にも役立つことがあります。