PostgreSQL Connection Pool Lab
PostgreSQL connection pool lab 的核心責任是讓讀者看到 connection pressure 如何從 application pool 傳到 PostgreSQL backend process。這篇承接 Connection Scaling 與 PgBouncer Config。
本篇的範圍是在 local lab 上比較 application 直連 PostgreSQL 與經過 PgBouncer transaction pooling 時的 backend 數、重現 pool exhaustion 時 client 在 pooler 排隊,並把 pg_stat_activity 與 PgBouncer SHOW POOLS 的結果寫成 failure note。
Baseline Direct Connections
Baseline direct connections 的核心責任是先看 application 直連 PostgreSQL 時的 backend 數。
1export DATABASE_URL="postgres://lab_admin:lab_admin_pw@localhost:54329/appdb?sslmode=disable"
2psql "$DATABASE_URL" -c "SELECT count(*) FROM pg_stat_activity WHERE datname = current_database();"用背景 psql 開五個同時在執行 pg_sleep(10) 的 session:
1for i in 1 2 3 4 5; do
2 psql "$DATABASE_URL" -c "SELECT pg_sleep(10);" &
3done
4psql "$DATABASE_URL" -c "SELECT state, count(*) FROM pg_stat_activity WHERE datname = current_database() GROUP BY state;"
5# state 是 active 的有 6 個:五個 pg_sleep session,加上這一句查詢自己這一步證明每個 client session 會占用 PostgreSQL backend process。
Add PgBouncer
Add PgBouncer 的核心責任是把 client connection 與 server connection 拆開。以下 compose fragment 可加入 local lab:
1 pgbouncer:
2 image: edoburu/pgbouncer:latest
3 environment:
4 DB_HOST: postgres
5 DB_USER: lab_admin
6 DB_PASSWORD: lab_admin_pw
7 DB_NAME: appdb
8 POOL_MODE: transaction
9 MAX_CLIENT_CONN: 100
10 DEFAULT_POOL_SIZE: 5
11 # PostgreSQL 16 的密碼以 SCRAM 儲存;image 預設 md5 時 PgBouncer 連 backend 回 wrong password type
12 AUTH_TYPE: scram-sha-256
13 # admin console(pgbouncer 虛擬 database)只允許這裡列的 user,image 預設只有 postgres
14 ADMIN_USERS: lab_admin
15 ports:
16 - "64329:5432"啟動後設定 pooler URL:
1export POOL_URL="postgres://lab_admin:lab_admin_pw@localhost:64329/appdb?sslmode=disable"Compare Pool Behavior
Compare pool behavior 的核心責任是觀察 client 多、server 少的效果。
1for i in $(seq 1 20); do
2 psql "$POOL_URL" -c "SELECT pg_sleep(1);" &
3done
4psql "$DATABASE_URL" -c "SELECT state, count(*) FROM pg_stat_activity WHERE datname = current_database() GROUP BY state;"再進 PgBouncer admin console;compose 裡的 ADMIN_USERS: lab_admin 讓 lab_admin 能連 pgbouncer 這個虛擬 database:
1psql "postgres://lab_admin:lab_admin_pw@localhost:64329/pgbouncer?sslmode=disable" -c "SHOW POOLS;"驗收重點是:client workload 增加時,PostgreSQL backend 數量被 pool size 控制,排隊發生在 pooler 層。
Pool Exhaustion
Pool exhaustion 的核心責任是看過載時 client 在 pooler 排隊等待。這組參數下 50 個 client 全部成功,看得到的是 SHOW POOLS 的 cl_waiting 與 psql 印出的 No server connection available in postgres backend, client being queued;錯誤要等 client 在隊伍裡待超過 PgBouncer 的 query_wait_timeout(預設 120 秒)才出現。
1for i in $(seq 1 50); do
2 psql "$POOL_URL" -c "BEGIN; SELECT pg_sleep(5); COMMIT;" &
3done觀察:
1psql "$DATABASE_URL" -c "SELECT count(*) FROM pg_stat_activity WHERE datname = current_database();"
2psql "postgres://lab_admin:lab_admin_pw@localhost:64329/pgbouncer?sslmode=disable" -c "SHOW POOLS;"Pool exhaustion 的 evidence 包含 waiting clients、timeout、application latency 與 error message。這些要接到 production alert。
Failure Note
Failure note 的核心責任是把 lab 結果轉成 runbook。記錄三件事:
- Direct connection baseline backend 數。
- PgBouncer transaction pooling 下 server connection 數。
- Pool exhaustion 時的 latency / error / queue。
若 application 使用 session state、prepared statement、temp table 或 advisory lock,還要補 transaction pooling compatibility matrix。
下一步路由
完成本篇後,回到 Connection Pooler Comparison 做選型;要看 PgBouncer production 設定讀 PgBouncer Config。