Connection Pooling — Database

Connection pool adalah kumpulan koneksi database yang sudah dibuka dan di-reuse oleh aplikasi — alih-alih membuka koneksi baru setiap request. Ini praktik stand

Connection pool adalah kumpulan koneksi database yang sudah dibuka dan di-reuse oleh aplikasi — alih-alih membuka koneksi baru setiap request. Ini praktik standar untuk aplikasi production.

Kenapa Connection Pooling Wajib?

Membuka koneksi database itu mahal — biasanya 50–200ms untuk TCP handshake, authentication, SSL negotiation. Untuk request API yang idealnya <100ms total, connection overhead ini mematikan.

Juga: database punya limit maksimum koneksi. PostgreSQL default max_connections = 100. Kalau aplikasi kamu punya 50 worker × 2 koneksi per request = sudah mentok. Request ke-51 harus antri atau gagal.

Tanpa pooling:             Dengan pooling:
Request → connect (100ms)  Request → ambil idle conn (<1ms)
         → query (5ms)              → query (5ms)
         → disconnect               → kembalikan ke pool

Total: ~105ms              Total: ~6ms

Built-in Pool (per aplikasi)

Framework modern punya pool built-in:

// Laravel (config/database.php)
"mysql" => [
    "driver" => "mysql",
    // ...
    "options" => [
        PDO::ATTR_PERSISTENT => true,  // reuse connections
    ],
],
// Node.js with pg
const { Pool } = require("pg");
const pool = new Pool({
  host: "localhost",
  database: "mydb",
  max: 20,            // max connection dalam pool
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
});

// Setiap pool.query() ambil dari pool, kembalikan otomatis setelah selesai
const result = await pool.query("SELECT * FROM users WHERE id = $1", [id]);

Tapi built-in pool per-process. Kalau kamu jalanin 10 worker Laravel/Node, masing-masing punya pool sendiri. Database harus handle 10 × pool-size connection total.

External Pooler: PgBouncer / ProxySQL

Untuk production skala besar, pasang connection pooler eksternal di depan database. Aplikasi connect ke pooler, pooler me-multiplex ke database.

App 1 ─┐
App 2 ─┼─→ PgBouncer (port 6432) ─→ PostgreSQL (port 5432)
App 3 ─┤   [1000 incoming conns]     [20 outgoing conns]
App N ─┘

Manfaat:

3 Mode PgBouncer

Mode Connection Sharing Cocok untuk Caveat
Session 1 client = 1 server conn selama session Legacy apps Hampir tidak ada benefit vs no-pool
Transaction 1 server conn di-share antar client per transaction REST API, web apps Tidak bisa pakai prepared statements, SET statements
Statement Rotate conn per query Stateless sangat strict Banyak fitur Postgres tidak jalan

Default yang dipakai production: transaction mode. 90% aplikasi web cocok.

Sizing the Pool — Aturan Praktis

Terlalu kecil = antrian. Terlalu besar = memory wasted di DB.

Formula PostgreSQL ([^wiki]):

connections = ((core_count * 2) + effective_spindle_count)

Untuk SSD 4-core: (4 * 2) + 1 = 9 connection per pool instance bisa sangat cukup.

Myth: makin banyak pool size = makin cepat. Reality: kalau DB cuma bisa proses 10 query paralel, pool 1000 cuma menciptakan bottleneck di sisi DB.

Monitoring — Apa yang Harus Dipantau

-- PostgreSQL: connection aktif saat ini
SELECT count(*), state FROM pg_stat_activity GROUP BY state;

-- Max connection setting
SHOW max_connections;

-- Connection yang idle in transaction (leaky!)
SELECT pid, state, query_start, query FROM pg_stat_activity
WHERE state = 'idle in transaction'
  AND query_start < now() - interval '5 minutes';

"idle in transaction" adalah red flag — aplikasi lupa commit/rollback, koneksi stuck tidak bisa dipakai orang lain. Set idle_in_transaction_session_timeout = 60s di postgresql.conf untuk auto-kill.

Checklist Production

[^wiki]: PostgreSQL wiki "Number of Database Connections" — baca untuk formula yang lebih presisi.

Yang akan kamu pelajari