Open4
【記事の草案】DBのコネクションプールについてちゃんと理解する
前提知識
アプリのコードからデータベースにアクセスする際、通常、次のような手順を踏む。
- アプリとデータベースとの接続を確立する
- トランザクションを開始する
- SQLを実行する
- トランザクションを終了する(コミットまたはロールバック)
- データベースとの接続を切断する
コネクションプーリングとは?
コネクションプールとは、データベースへの接続を確立した状態で保持しておき、そのコネクションを再利用することでデータベース接続のオーバーヘッドを削減する機能のことである。
先ほどの処理において、1.
と5.
によるオーバーヘッドが大きいため、コネクションプールを使用して接続を保持し、これを再利用する。
コネクションプールの数はどのように決めたら良いのか?
コネクションをプールしておくということは、それだけ並列に処理を実行できるということである。
したがって、コネクションプールの数を決める際には、以下の要因を考慮すると良い。
- DBサーバーのスレッド数:コネクションプールの数が、DBサーバーが処理できる並列スレッド数を超えないように設定する。一般的には、1台のDBサーバーの場合、DBサーバーのCPUコア数に基づいてコネクションプールの数を設定することが多い。
- アプリケーションの同時接続数:アプリケーションがどれだけの同時接続を必要とするかも重要である。
より深く理解するために
railsではどうなってる?
- config/database.ymlでコネクションプーリングの設定ができる。
production:
adapter: postgresql
encoding: unicode
database: my_database
pool: 15
timeout: 3000 # コネクション取得の最大待ち時間を3秒に設定
reaping_frequency: 30 # アイドル状態になったコネクションプールを破棄する頻度を30秒に設定
checkout_timeout: 2000 # コネクション取得時のタイムアウトを2秒に設定
- 実際に処理を行っているのは、以下のクラス
実例やDeep Dive
上記の記事の、コネクションプーリングのアルゴリズムがわかりやすかったので抜粋。
コネクションプーリングのアルゴリズムの説明
- 既存のコネクションが利用可能であれば、それをすぐに返す。
- プールがキャパシティいっぱいの場合は、キューで待機する。
checkout_timeout
を超過したらエラーを発生させる。超過していない場合は、利用可能なコネクションを返す。 - プールがキャパシティいっぱいでない場合は、新しいコネクションを作成する。
connect_timeout
を超過したらエラーを発生させる。 - 新しいコネクションが確立されたら、それを返す。
引用
Connection Pooling Algorithm
The following pseudocode is the algorithm for how ActiveRecord retrieves connections from the pool to perform database queries.
if there are existing connections to the database available:
return one of the existing connections
if the pool is at capacity:
wait on the queue, raise exception if `checkout_timeout` has elapsed
return one of the now available connections
# pool is not at capacity
try to create a new connection, raise exception if `connect_timeout` has elapsed
# connection to database established
return new connection
This is loosely translated from the source code.
コネクションプーリングを自前実装して見たいな
参考