Skip Navigation
Show nav
Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku のアーキテクチャ
    • Dyno (アプリコンテナ)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • Developer Tools
    • コマンドライン
    • Heroku VS Code Extension
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリーとインテグレーション
    • 継続的統合
  • 言語サポート
    • Node.js
      • Working with Node.js
      • Node.js Behavior in Heroku
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails のサポート
      • Bundler の使用
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Python でのバックグランドジョブ
      • Python Behavior in Heroku
      • Django の使用
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Maven の使用
      • Spring Boot の使用
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres スターターガイド
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
      • Migrating to Heroku Postgres
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • その他のデータストア
  • AI
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
      • シングルサインオン (SSO)
    • Private Space
      • インフラストラクチャネットワーキング
    • コンプライアンス
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Salesforce とのインテグレーション
  • 言語サポート
  • Ruby
  • Ruby Behavior in Heroku
  • ActiveRecord による Ruby での並列性とデータベース接続

ActiveRecord による Ruby での並列性とデータベース接続

日本語 — Switch to English

この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。

最終更新日 2024年04月26日(金)

Table of Contents

  • 接続プール
  • マルチスレッドサーバー
  • マルチプロセスサーバー
  • データベース接続の最大数
  • 必要な接続数の計算
  • アクティブな接続の数
  • バックグラウンドワーカー
  • 不適切な接続
  • PgBouncer を使用した接続の制限

Puma​ などのマルチスレッド Web サーバーまたは Unicorn​ などのマルチプロセス Web サーバーを使用して並列性を向上させる場合は、アプリがデータベースに対して保持する接続の数や、データベースが受け付けることができる接続の数に注意する必要があります。各スレッドまたはプロセスには、データベースへの異なる接続が必要です。これに対応するために、Active Record には、同時に複数の接続を保持できる接続プールが用意されています。

接続プール

デフォルトでは、Rails (Active Record) は、新しいスレッドまたはプロセスが SQL クエリを使用してデータベースにアクセスしようとした場合にのみ接続を作成します。Active Record では、アプリケーションあたりの接続の合計数がデータベース設定 pool​ によって制限されます。これは、アプリがデータベースに対して保持できる接続の最大サイズです。データベース接続プールのデフォルトの最大サイズは 5 です。使用可能な数を超える接続を使用しようとすると、Active Record によってブロックされ、プールの接続の待ち状態になります。接続を取得できない場合は、タイムアウトエラーがスローされます。これは次のようになります。

ActiveRecord::ConnectionTimeoutError - could not obtain a database connection within 5 seconds. The max pool size is currently 5; consider increasing it

このエラーを回避するには、接続設定をカスタマイズすることによって接続プールのサイズを手動で変更できます。その方法は似ていますが、接続設定の場所は、マルチスレッドまたはマルチプロセスのどちらの Web サーバーかによって異なる場合があります。

マルチスレッドサーバー

複数のスレッドで並列性を実現するサーバーの場合は、イニシャライザを使用してデータベースプールを設定することをお勧めします。Rails アプリケーションは起動すると、イニシャライザ内のコードを実行し、カスタマイズを使用して接続を確立します。

Rails 4.1+ の場合は、次の値を config/database.yml​ で直接設定できます。

production:
  url:  <%= ENV["DATABASE_URL"] %>
  pool: <%= ENV["DB_POOL"] || ENV['RAILS_MAX_THREADS'] || 5 %>

その他の古いバージョンの Rails を使用している場合は、イニシャライザを使用する必要があります。

# config/initializers/database_connection.rb

# Use config/database.yml method if you are using Rails 4.1+
Rails.application.config.after_initialize do
  ActiveRecord::Base.connection_pool.disconnect!

  ActiveSupport.on_load(:active_record) do
    config = ActiveRecord::Base.configurations[Rails.env] ||
                Rails.application.config.database_configuration[Rails.env]
    config['pool']              = ENV['DB_POOL']      || ENV['RAILS_MAX_THREADS'] || 5
    ActiveRecord::Base.establish_connection(config) # Establish connection is not needed for Rails 5.2+ https://github.com/rails/rails/pull/31241
  end
end

すでにイニシャライザを使用している場合は、database.yml​ 方式へできるだけ早く切り替える必要があります。Unicorn や Puma (ハイブリッドモード) などのフォーキング Web サーバーを使用している場合、イニシャライザを使用するにはコードの複製が必要になります。イニシャライザ方式は、発生している内容に関する混乱が生じることがあり、サポートチケットが大量に消費される原因となります。

Puma Web サーバー​を使用している場合は、pool​ 値を同等の ENV['RAILS_MAX_THREADS']​ に設定することをお勧めします。複数のプロセスを使用している場合は、各プロセスに独自のプールが含まれるため、ワーカープロセスが ENV['RAILS_MAX_THREADS']​ を超えない限りはこの設定で十分です。

マルチプロセスサーバー

Unicorn などのフォーキングサーバーの場合、マスタープロセスは Rails アプリケーションを起動 (さらに、イニシャライザをすべて実行) してからワーカーをフォークします。このため、マスタープロセスの before_fork​ で接続を切断した後、after_fork​ ブロックで接続を再確立することが必要です。

# config/unicorn.rb
before_fork do |server, worker|
  # other settings
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end
end

after_fork do |server, worker|
  # other settings
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection # Establish connection is not needed for Rails 5.2+ https://github.com/rails/rails/pull/31241
  end
end

Unicorn の場合、この接続設定は「Unicorn を使用した Rails アプリケーションのデプロイ​」ガイドで説明されている通常の推奨される設定への追加になります。

Rails 4.1+ を使用している場合、ActiveRecord::Base.establish_connection​ では、config/database.yml​ に保存されている接続情報が使用されます。それ以外の場合は、一貫した接続情報を確保するために、イニシャライザでこの動作を複製する必要があります。

# config/unicorn.rb

# Use config/database.yml method if you are using Rails 4.1+
after_fork do |server, worker|
  # other settings
  if defined?(ActiveRecord::Base)
    config = ActiveRecord::Base.configurations[Rails.env] ||
                Rails.application.config.database_configuration[Rails.env]
    config['pool'] = ENV['DB_POOL'] || 5
    ActiveRecord::Base.establish_connection(config)
  end
end

pool​ を 5 つの接続、つまり DB_POOL​ 環境変数で指定された値に設定していることに注意してください。これで、Heroku で環境設定を設定することによって接続プールサイズを設定できます。たとえば、これを 10 に設定したい場合は、次のように実行します。

$ heroku config:set DB_POOL=10

これにより、各 dyno に 10 個の開かれた接続が割り当てられるわけではなく、新しい接続が必要な場合は、Rails プロセスあたり最大 10 個が使用されるまで新しい接続が作成されるようになるだけです。

プール内に十分な接続が存在する場合でも、データベースには、許可される接続の最大数がある可能性があります。

データベース接続の最大数

Heroku では、マネージド Postgres​ データベースが提供されます。階層型データベースごとにさまざまな接続制限があります。Essential 層データベースは 20 個の接続に制限​されています。Standard 層以上のデータベースの制限数はそれ以上​です。データベースは、アクティブな接続の最大数に達した後、新しい接続を受け付けなくなります。制限に達した結果、アプリケーションからの接続がタイムアウトになり、例外が発生する可能性があります。

スケールアウトするときは、アプリケーションに必要なアクティブな接続の数に注意することが重要です。各 dyno で 5 つのデータベース接続が許可されている場合は、より堅牢なデータベースのプロビジョニングが必要になるまでに、4 つの dyno にしかスケールアウトできません。

これで、接続プールを設定する方法や、データベースで処理できる接続の数を見つける方法がわかったので、各 dyno に必要な接続の適切な数を計算する必要があります。

必要な接続数の計算

アプリケーションコードでスレッドを手動で作成していない場合は、Web サーバーの設定を使用して、必要な接続の数を導き出すことができます。Unicorn Web サーバーは、複数のプロセスを使用してスケールアウトします。アプリケーションで新しいスレッドを開いていない場合は、各プロセスが 1 つの接続を受け取ります。そのため、Unicorn の設定ファイルで worker_processes​ が 3​ に設定されている場合は、次のようになります。

worker_processes 3

これにより、アプリはワーカーに 3 つの接続を使用します。つまり、各 dyno には 3 つの接続が必要になります。"Dev" プランを使用している場合は、6 つの dyno にスケールアウトできます。これは、アクティブなデータベース接続の数が最大 20 個のうちの 18 個になることを示します。ただし、一部の接続が不適切な状態または不明な状態になる可能性があります。このため、アプリケーションの pool​ を 1​ または 2​ のどちらかに設定して、ゾンビ接続がデータベースを飽和させないようにすることをお勧めします。後述の「不適切な接続」のセクションを参照してください。

別の Web サーバーである Puma​ は、複数 (デフォルトでは 16) のスレッドを使用して並列性を取得します。つまり、例外なしで操作するには、プール内に 16 個の接続が必要になります。dyno がこれらの 16 個のスレッドのすべてを十分には活用していない可能性があるため、チューニングによって最適な数を見つけ、それを Procfile​ で指定することができます。Puma で 5 つのスレッド、つまり最大 5 つの接続のみを使用するようにしたい場合は、次のように最大 5 つのスレッド 0:5​ を使用するように設定できます。

web:  bundle exec puma  -t 0:5 -p $PORT -e ${RACK_ENV:-development}

どのアプリケーションにもそれぞれ異なるパフォーマンス特性や異なる要件があります。アプリのスレッドの数を適切にチューニングするには、本番同様の環境またはステージング環境でアプリの負荷をテストする必要があります。

アクティブな接続の数

開発環境では、データベースをチェックすることにより、アプリケーションによって取得される接続の数を確認できます。

$ bundle exec rails dbconsole

これにより、開発データベースへの接続が開かれます。その後、次を実行して Postgres データベースへの接続の数を確認できます。

select count(*) from pg_stat_activity where pid <> pg_backend_pid() and usename = current_user;

これにより、そのデータベース上の接続の数が返されます。

 count
-------
   5
(1 row)

接続は低速で開かれるため、localhost​ にある実行中のアプリケーションを、カウントが増えなくなるまで複数回ヒットする必要があります。開発セットアップでは、アプリによる新しい接続の作成に必要な負荷を生成できない可能性があるため、正確なカウントを得るには、そのデータベースクエリを本番データベースの内部で実行する必要があります。

バックグラウンドワーカー

worker​ プロセスタイプを使用し、Sidekiq​ などのバックグラウンドワーカーライブラリを使用している場合は、dyno タイプごとに設定を変えることが必要になる場合があります。デフォルトでは、Sidekiq は 10 個のスレッド​を使用します。つまり、ワーカー上のデータベースを 10 を超えるスレッド数にするか、または Sidekiq プロセスで使用されるスレッド数が少なくなるように設定する必要があります。

Rails アプリが前のセクションから設定されている場合は、RAILS_MAX_THREADS​ を別の値に設定できます。次に例を示します。

worker: RAILS_MAX_THREADS=${SIDEKIQ_RAILS_MAX_THREADS:-10} bundle exec sidekiq

この例では、heroku config:set SIDEKIQ_RAILS_MAX_THREADS=5​ を実行する必要があります。

代わりに、Sidekiq での接続の数を変更したい場合は、Sidekiq を -c​ フラグで起動し、SIDEKIQ_CONCURRENCY​ などの別の環境設定を使用できます。

worker: bundle exec sidekiq -c ${SIDEKIQ_CONCURRENCY:-5}

この例では、バックグラウンドジョブを処理するために 5 つのスレッドのみを使用するよう Sidekiq に指示しています。

不適切な接続

接続がハングアップしたり、"不適切な" 状態になったりすることがあります。つまり、接続は使用できなくなるが、開かれたままになります。Unicorn などのマルチプロセス Web サーバーを実行している場合は、通常は 3 つのデータベース接続を消費する 3 Worker dyno が、時間の経過と共に 15 個もの接続 (プールあたり 5 つのデフォルト接続× 3 つの Worker) を保持するようになる可能性があります。この脅威を制限するには、接続プールを 1​ または 2​ に減らし、Rails 4 で使用可能な接続リーピングを有効にします。ただし、この機能は、このバグレポートの後にデフォルトで無効​になりました。

'reaping_frequency'​ は、Active Record に、接続がハングアップまたは停止しているかどうかを N 秒おきに確認し、それを終了するよう指示できます。時間の経過と共にアプリケーションでいくつかのハングアップした接続が発生する可能性はありますが、コード内のどこかの部分がハングアップした接続の原因になっている場合、リーパーはこの問題に対する永続的な解決になりません。

PgBouncer を使用した接続の制限

データベース接続の制限に達するまで、追加の dyno を使用して引き続きアプリケーションをスケールアウトできます。この時点に達する前に、PgBouncer buildpack​ を使用して、各 dyno に必要な接続の数を制限することをお勧めします。

PgBouncer では、データベーストランザクションで共有される接続のプールが保持されます。これにより、Postgres への接続 (通常は開いており、アイドル状態) が最小限に維持されます。ただし、トランザクションプーリングでは、名前付きプリペアドステートメント、セッションアドバイザリロック、リッスン/通知、またはセッションレベルで操作するその他の機能を使用できなくなります。詳細は、「PgBouncer buildpack FAQ for full list of limitations​」(制限の完全なリストに関する PgBouncer buildpack の FAQ) を参照してください。

多くのフレームワークでは、PgBouncer を使用するためにプリペアドステートメントを無効にする​必要があります。その後、PgBouncer buildpack をアプリに追加します。

プリペアドステートメントを無効にするか、またはフレームワークでそれが使用されていないことを確認する前に続行しないでください。Rails 3+ ではプリペアドステートメントが使用されます。

$ heroku buildpacks:add heroku/pgbouncer

第一言語の buildpack の記述があることも確認してください。

$ heroku buildpacks
1. heroku/ruby
2. heroku/pgbouncer

Ruby で想定されるものとは異なる言語を使用している場合、1 行目は異なります。

ここで、PgBouncer を起動するように Procfile​ を変更する必要があります。Procfile​で、コマンド bin/start-pgbouncer-stunnel​ を web​ エントリの先頭に追加します。そのため、Procfile​ が

web: bundle exec puma -C config/puma.rb

であった場合は、次のようになります。

web: bin/start-pgbouncer-stunnel bundle exec puma -C config/puma.rb

結果を Git にコミットし、ステージングアプリでテストした後、本番環境にデプロイします。

デプロイ時、出力には次の内容が表示されます。

=====> Detected Framework: pgbouncer-stunnel

関連カテゴリー

  • Ruby Behavior in Heroku
Ruby データベースの自動プロビジョニング Ruby のデフォルト Web サーバー

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices