013: PgBouncer transaction pooling on localhost:6432
Serverless clients -> many short connections, few TPS. pool_mode= transaction, max_client_conn=300, default_pool_size=20 (+reserve 5) matching max_connections=30. max_prepared_statements=200 for ORM prepared statements. localhost-only until remote-access migration (roadmap 015). README table + notes updated.
This commit is contained in:
@@ -52,8 +52,22 @@ For a private repo you need an auth strategy:
|
|||||||
| 006 | install-postgres | PG 18 via PGDG repo, cluster on the disk |
|
| 006 | install-postgres | PG 18 via PGDG repo, cluster on the disk |
|
||||||
| 007 | postgres-admin-role | iwanhae OS user -> PG superuser (peer auth) |
|
| 007 | postgres-admin-role | iwanhae OS user -> PG superuser (peer auth) |
|
||||||
| 008 | create-db-iwanhae | database `iwanhae` owned by admin role |
|
| 008 | create-db-iwanhae | database `iwanhae` owned by admin role |
|
||||||
|
| 010 | tune-postgres | 1GB stability: conns=30, cache hint, timeouts, temp_file_limit |
|
||||||
|
| 011 | postgres-observability | pg_stat_statements, slow-log 500ms, io timing |
|
||||||
|
| 012 | tune-cpu | parallel caps + jit=off for shared 2 vCPU |
|
||||||
|
| 013 | install-pgbouncer | :6432 transaction pooling, localhost-only |
|
||||||
|
|
||||||
|
## PgBouncer notes (013)
|
||||||
|
|
||||||
|
Serverless clients (many connections, few TPS) connect to PgBouncer
|
||||||
|
(`127.0.0.1:6432`, transaction mode) which opens at most ~25 real
|
||||||
|
PostgreSQL backends - matching `max_connections=30` from 010 with room
|
||||||
|
for admin sessions. Remote access is deliberately not opened yet; when
|
||||||
|
it is: create an app role with a SCRAM password, export its verifier into
|
||||||
|
`/etc/pgbouncer/userlist.txt` (snippet in 013's header), flip
|
||||||
|
`listen_addr` and open the firewall.
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- `010-tune-postgres` - 1GB tuning (shared_buffers=128MB, work_mem=4MB,
|
- `015-remote-access` - app role + SCRAM credentials, pgbouncer
|
||||||
max_connections=30, ...)
|
`listen_addr` + userlist.txt, pg_hba for the app CIDR, TLS, firewall
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 013-install-pgbouncer - Connection pooling for serverless clients.
|
||||||
|
#
|
||||||
|
# Workload: a handful of TPS, but many (serverless) clients -> many short
|
||||||
|
# connections. PgBouncer fronts PostgreSQL in transaction mode; PostgreSQL
|
||||||
|
# itself keeps max_connections=30 (010). Server connections go over TCP
|
||||||
|
# 127.0.0.1:5432 so the existing pg_hba `host ... scram-sha-256` line applies
|
||||||
|
# unchanged (PgBouncer re-uses the client's SCRAM verifier from userlist.txt).
|
||||||
|
#
|
||||||
|
# Listens on 127.0.0.1:6432 ONLY - remote access is a later migration
|
||||||
|
# (roadmap): flip listen_addr, populate userlist.txt with an app role, open
|
||||||
|
# the firewall. Until then nothing can connect through it; that is expected.
|
||||||
|
#
|
||||||
|
# Populating userlist.txt when the app role exists (SCRAM pass-through):
|
||||||
|
# runuser -u postgres -- psql -tAc \
|
||||||
|
# "SELECT '\"'||rolname||'\" \"'||rolpassword||'\"' \
|
||||||
|
# FROM pg_authid WHERE rolname='APP' AND rolpassword LIKE 'SCRAM%'" \
|
||||||
|
# | sudo tee -a /etc/pgbouncer/userlist.txt && sudo systemctl reload pgbouncer
|
||||||
|
#
|
||||||
|
# up: install package (PGDG/Debian repo), write ini + empty userlist,
|
||||||
|
# enable + restart service, verify it accepts connections
|
||||||
|
# down: stop + disable service, purge package, remove config
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
INI=/etc/pgbouncer/pgbouncer.ini
|
||||||
|
USERLIST=/etc/pgbouncer/userlist.txt
|
||||||
|
LOG=/var/log/postgresql/pgbouncer.log
|
||||||
|
|
||||||
|
write_ini() {
|
||||||
|
install -d -o postgres -g postgres -m 750 /etc/pgbouncer
|
||||||
|
cat > "$INI" <<'EOF'
|
||||||
|
;; managed by sysmig 013-install-pgbouncer - serverless connection pooler
|
||||||
|
[databases]
|
||||||
|
;; server side: TCP + scram against stock pg_hba (127.0.0.1/32 line)
|
||||||
|
iwanhae = host=127.0.0.1 port=5432 dbname=iwanhae
|
||||||
|
|
||||||
|
[pgbouncer]
|
||||||
|
;; --- client side: localhost only until the remote-access migration ---
|
||||||
|
listen_addr = 127.0.0.1
|
||||||
|
listen_port = 6432
|
||||||
|
unix_socket_dir = /var/run/postgresql
|
||||||
|
|
||||||
|
auth_type = scram-sha-256
|
||||||
|
auth_file = /etc/pgbouncer/userlist.txt
|
||||||
|
admin_users = iwanhae
|
||||||
|
|
||||||
|
;; --- pooling: many short serverless clients, few real workers ---
|
||||||
|
pool_mode = transaction
|
||||||
|
max_client_conn = 300
|
||||||
|
default_pool_size = 20
|
||||||
|
reserve_pool_size = 5
|
||||||
|
reserve_pool_timeout = 3
|
||||||
|
|
||||||
|
;; named prepared statements in transaction mode (ORMs need this, >=1.22)
|
||||||
|
max_prepared_statements = 200
|
||||||
|
ignore_startup_parameters = extra_float_digits
|
||||||
|
|
||||||
|
;; --- server connection lifecycle ---
|
||||||
|
server_reset_query = DISCARD ALL
|
||||||
|
server_idle_timeout = 60
|
||||||
|
|
||||||
|
;; --- process ---
|
||||||
|
logfile = /var/log/postgresql/pgbouncer.log
|
||||||
|
pidfile = /var/run/postgresql/pgbouncer.pid
|
||||||
|
user = postgres
|
||||||
|
EOF
|
||||||
|
chown postgres:postgres "$INI"
|
||||||
|
chmod 640 "$INI"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
up)
|
||||||
|
if ! dpkg -s pgbouncer >/dev/null 2>&1; then
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y pgbouncer >/dev/null
|
||||||
|
echo " pgbouncer installed"
|
||||||
|
else
|
||||||
|
echo " pgbouncer already installed"
|
||||||
|
fi
|
||||||
|
write_ini
|
||||||
|
# empty placeholder; populated by the future remote-access migration
|
||||||
|
touch "$USERLIST"
|
||||||
|
chown postgres:postgres "$USERLIST"
|
||||||
|
chmod 640 "$USERLIST"
|
||||||
|
systemctl enable pgbouncer >/dev/null
|
||||||
|
systemctl restart pgbouncer
|
||||||
|
ok=0
|
||||||
|
for _ in $(seq 1 10); do
|
||||||
|
if pg_isready -h 127.0.0.1 -p 6432 -q 2>/dev/null; then ok=1; break; fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
[[ $ok -eq 1 ]] || { echo "FATAL: pgbouncer not accepting on 127.0.0.1:6432 - check $LOG" >&2; exit 1; }
|
||||||
|
echo " listening on 127.0.0.1:6432 (transaction pool, ready for userlist entries)"
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
[[ -f $INI ]] || { echo "DRIFT $INI missing"; exit 1; }
|
||||||
|
systemctl is-active --quiet pgbouncer || { echo "DRIFT pgbouncer service not active"; exit 1; }
|
||||||
|
pg_isready -h 127.0.0.1 -p 6432 -q 2>/dev/null \
|
||||||
|
|| { echo "DRIFT nothing accepting on 127.0.0.1:6432"; exit 1; }
|
||||||
|
grep -q '^pool_mode = transaction' "$INI" || { echo "DRIFT pool_mode not transaction"; exit 1; }
|
||||||
|
grep -q '^listen_addr = 127.0.0.1' "$INI" || { echo "DRIFT listen_addr changed (remote access migration?)"; exit 1; }
|
||||||
|
echo "OK pgbouncer on 127.0.0.1:6432, transaction mode"
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
systemctl disable --now pgbouncer 2>/dev/null || true
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get purge -y pgbouncer >/dev/null
|
||||||
|
rm -rf /etc/pgbouncer "$LOG"
|
||||||
|
echo " pgbouncer stopped, purged, config removed"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user