はじめに
前回までの続きです。今回はコネクションプールについて学んでいきます!
たしか、コネクションプールはコネクションを確保しておいてそれを使い回すという考え方。コネクションを毎回貼り直すとコストがかかるので最初に一定の数結んでおいてそれを使い回すというやつ。
ユーザーが変わるたびにゲームキューブのコントローラーを毎回抜き差しすると大変だよね。だから、コントローラーは先につけておいて、コントローラーだけ変更するとゲームする時楽だよねってイメージで覚えている。
今回も座学の範囲はChatGPTに教えてもらいます。情報が正しくない可能性もありますが、悪しからず。
🧩 コネクションプールとは?
PostgreSQL における コネクション(接続) は、
「アプリ ⇨ データベース」の間に作られる通信の橋のことです。
PostgreSQL は「1接続 = 1プロセス(バックエンドプロセス)」なので、
接続を開くたびに新しいプロセスが生成されます。
これを毎回作るのは重たい…
→ だから、一度作った接続を プール(pool) に保持して再利用します。
🧠 ゲームの世界に置き換えると
| たとえ | PostgreSQLの世界 |
|---|---|
| ゲーム機本体 | PostgreSQLサーバ(Postmaster + バックエンドプロセス) |
| コントローラー | DBコネクション(アプリ⇨DB接続) |
| コントローラーを毎回抜き差し | 接続を毎回新しく作る(非効率) |
| コントローラーを常に挿しておく | 接続をプールして再利用 |
| コントローラーが足りない時に待つ | プール上限に達したので空きを待機 |
🧮 イメージ図
・APIは毎回新しい接続を作らず、プールにある接続を「借りて使う」。
・使い終わったら、切断せずに「プールに返す」。
・次のリクエストが来たら、また使い回す。
Hands-on
コネクションプールの数を1、3、5で実験。
package main
import (
"database/sql"
"fmt"
"log"
"sync"
"time"
_ "github.com/lib/pq"
)
// コネクションプールのサイズ
const poolSize = 1
func main() {
dsn := "postgres://user:password@localhost:5432/mydatabase?sslmode=disable"
db, err := sql.Open("postgres", dsn)
if err != nil {
log.Fatal("DB接続エラー:", err)
}
defer db.Close()
// 🔧 コネクションプールの設定
db.SetMaxOpenConns(poolSize) // 最大同時接続数(PostgreSQL側で3バックエンドまで)
db.SetMaxIdleConns(poolSize) // アイドル状態で保持する接続数
db.SetConnMaxLifetime(30 * time.Second) // 接続の寿命(任意)
fmt.Println("=== コネクションプール実験開始 プール数1 ===")
var wg sync.WaitGroup
// 🔁 5つの同時クエリを実行してみる
for i := 1; i <= 5; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
start := time.Now()
// 実際に時間のかかるクエリを投げる
_, err := db.Exec("SELECT pg_sleep(3)") // 3秒間スリープ
if err != nil {
fmt.Printf("クエリ%d エラー: %v\n", n, err)
return
}
fmt.Printf("クエリ%d 完了!(経過: %.1fs)\n", n, time.Since(start).Seconds())
}(i)
}
wg.Wait()
fmt.Println("=== 実験終了 ===")
}
~/develop/postgresql_study/sample-go (main)$ go run main.go
=== コネクションプール実験開始 プール数1 ===
クエリ2 完了!(経過: 3.1s)
クエリ1 完了!(経過: 6.1s)
クエリ3 完了!(経過: 9.1s)
クエリ5 完了!(経過: 12.1s)
クエリ4 完了!(経過: 15.1s)
=== 実験終了 ===
→処理フローは上です。コネクションプールは1本なので、5本✖︎3秒なので15秒待ちます。
コネクションプールの数を3にして実行。
~/develop/postgresql_study/sample-go (main)$ go run main.go
=== コネクションプール実験開始 プール数 3 ===
クエリ1 完了!(経過: 3.1s)
クエリ5 完了!(経過: 3.1s)
クエリ2 完了!(経過: 3.1s)
クエリ4 完了!(経過: 6.1s)
クエリ3 完了!(経過: 6.1s)
=== 実験終了 ===
コネクションプールの数を5にして実行。
~/develop/postgresql_study/sample-go (main)$ go run main.go
=== コネクションプール実験開始 プール数 5 ===
クエリ3 完了!(経過: 3.1s)
クエリ2 完了!(経過: 3.1s)
クエリ4 完了!(経過: 3.1s)
クエリ5 完了!(経過: 3.1s)
クエリ1 完了!(経過: 3.1s)
=== 実験終了 ===
さいごに
コネクションプール理解できました!知識として持っていたのですが、実際に手を動かして理解するのは初めてだったので良かったです!!