FIG-088

コネクションプール — 受話器を上げたまま、使い回す

データベース 2026.09.07 公開 読了 約11分

アプリがDBに問い合わせるとき、実際のクエリの前に「つなぐ」という重い儀式があります。TCPの接続を張り、必要ならTLSを結び、ユーザー名とパスワードで認証する。ここまでで数十ミリ秒。肝心のクエリが1ミリ秒で終わるようなものでも、準備のほうが何十倍も重いという逆転が起きます。

コネクションプールは、この儀式を最初に数本ぶんだけ済ませ、あとは同じ回線を使い回す仕組みです。受話器を上げたままの電話線を何本か用意しておくコールセンターだと思ってください。図1で回線の本数を変えながらリクエストを流し、足りないとどうなるかまで見てください。

CONNECTION POOL — 受話器を上げたまま、使い回す
待ち行列 空きが出るまで並ぶ
回線 1 未接続
回線 2 未接続
回線 3 未接続
回線 4 未接続
回線 5 未接続
回線 6 未接続
平均の応答時間 —
接続を張った回数 0
待たされた件数 0
READY
6件のリクエストを、一斉に投げてみる
リクエストは1件あたりクエリに50msかかります。プールを使う場合、最初の1回だけ接続を張り、あとはその回線を使い回します。まずはこのまま流してみてください。
図1 — 回線を減らせば待ち行列が伸び、毎回つなぎ直せば準備だけで時間が溶ける

重いのはクエリではなく「つなぐこと」

DBへの接続は、TCPの3ウェイハンドシェイク、TLSの鍵交換、認証という3つの往復を伴います。同じデータセンター内でも数十ミリ秒、暗号化や認証が重ければもっとかかります。

図1で「毎回つなぎ直す」に切り替えて流すと、棒グラフの前半がオレンジ(接続)で埋まります。この時間はクエリの内容と一切関係なく、毎回まるごと払う固定費です。リクエストが増えるほど、この固定費が支配的になります。

プールは「先に払って、使い回す」

プールは起動時などにあらかじめ何本か接続を張っておき、リクエストが来たら空いている1本を貸し出します。処理が終わったら切断せずにプールへ返す。次のリクエストは接続の儀式ゼロで始められます。

図1の「接続を張った回数」を見比べてください。プールありなら回線の本数ぶんだけで済み、なしならリクエストの件数と同じ回数張り直しています。使い回せる回数が多いほど、この差は開きます。

足りなければ、待つ

プールの本数は同時に処理できる件数の上限でもあります。全部が貸出中のとき、次のリクエストは返却されるまで待たされます。図1で回線を1本にして流すと、待ち行列がずらりと伸びるのが分かります。

ここで「なら大きくすればいい」とはなりません。接続はDB側でもメモリとプロセスを消費するので、アプリの台数×プールサイズがDBの上限を超えれば、今度はDBのほうが倒れます。プールサイズはアプリの都合ではなくDBが支えられる総数から逆算する数字です。

そして、待ち時間に上限を設けるのが取得タイムアウトです。空きを待ち続けて全リクエストが固まるより、諦めてエラーを返したほうが被害が小さい――という判断が入っています。

用語ミニ辞書
コネクションプール
張った接続を保持して使い回す仕組み。接続の作り直しを避ける。
プールサイズ
保持する接続の本数。同時に処理できる件数の上限でもある。
貸出 / 返却
処理の間だけ1本を借り、終わったら切断せずプールへ戻すこと。
取得タイムアウト
空きを待てる時間の上限。超えたらエラーにして諦める。
プール枯渇
全部が貸出中で空きが出ない状態。待ち行列が伸び続ける。

まとめ

コネクションプールは「重い準備を先に済ませて、あとは使い回す」だけの発想です。効くのは接続の固定費が消えるから。そして本数は同時実行数の上限そのものなので、少なすぎれば待ち行列が伸び、多すぎればDBが潰れます。図1で本数を1本と6本に振ってみると、その両端がそのまま数字に出ます。