3秒でわかる
DB接続を毎回作らず、用意しておいた接続を貸し借りして使い回す仕組み。接続にかかる時間と同時接続数の両方を抑えられます。
もう少し詳しく
どういうものか
コネクションプールは、DBへの接続をあらかじめ何本か張ったまま保持しておき、リクエストごとに1本借りて、使い終わったら閉じずに返す仕組みです。アプリからは接続を作っているように見えますが、実際にはプールから貸し出されているだけで、TCPの接続と認証はすでに済んでいます。
なぜ必要か
DB接続を1本作るには、TCPのハンドシェイク、認証、サーバー側でのメモリ確保が必要で、往復のたびに数ミリ秒から数十ミリ秒かかります。1リクエストごとに張り直すと、この時間がそのまま応答時間に乗ります。加えて、DB側には同時接続数の上限があり、アクセスが増えたときに接続を作りすぎると、接続エラーでサービス全体が落ちます。プールは速度と上限の両方を守る仕組みです。
具体例
// <a href="/glossary/nodejs" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">Node.js</a> の pg の例。プールは起動時に1つだけ作る
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 10, // 同時に持つ接続の最大数
idleTimeoutMillis: 30_000, // 遊んでいる接続を閉じるまでの時間
});
app.get("/users", async (req, res) => {
const { rows } = await pool.query("SELECT id, name FROM users LIMIT 20");
res.json(rows);
});トランザクションのように同じ接続で複数の文を流したいときだけ、明示的に1本借りて必ず返します。
つまずきやすいところ
最大の事故は接続の返し忘れです。借りたまま返さないコードが1か所あると、プールが枯渇し、以降のリクエストが全部待ち状態になります。個別に借りる書き方をする場合は、後始末を必ずfinally相当の場所に書きます。
次に多いのが上限値の設定ミスです。アプリを4台に増やして各20本にすると、DBから見た同時接続は80本になります。DB側の上限を先に確認してから台数で割り当てます。プールを大きくすれば速くなると考えるのも誤りで、DBのCPU数を超える同時実行は待ち行列を長くするだけです。
覚え方
図書館の貸出と同じで、本は毎回買わず、借りて返します。返さない人がいると棚が空になります。
似た用語との違い
キャッシュは結果そのものを保存して再利用する仕組み、コネクションプールは通り道を再利用する仕組みです。返ってくるデータは毎回DBから取り直すため、更新の反映が遅れる心配はありません。