Connection Pooling: Maksimalkan Performa Database
Membuat koneksi database tidak gratis. Ada network handshake, authentication, memory di kedua sisi, dan sering kali process atau thread khusus di server. Connection pool menyimpan sejumlah koneksi yang sudah terbuka lalu meminjamkannya ke request. Jika dirancang baik, ia menurunkan latency dan melindungi database. Jika ceroboh, ia justru melipatgandakan overload.
Apa yang dikendalikan pool?
Saat aplikasi membutuhkan database, ia meminjam koneksi idle, menjalankan pekerjaan, lalu mengembalikannya. Jika semuanya sibuk, request menunggu di antrean pool hingga ada koneksi atau timeout tercapai. Jadi pool mengendalikan concurrency ke database; ia tidak membuat SQL yang lambat menjadi cepat.
Ada tiga batas yang saling berhubungan:
- ukuran pool per process aplikasi;
- jumlah process, pod, atau instance serverless; dan
- batas koneksi serta CPU, memory, dan I/O database.
Dua puluh koneksi mungkin aman pada satu instance API. Dengan lima puluh instance autoscale, setting sama berarti seribu koneksi bersamaan—cukup untuk menghabiskan database sebelum aplikasi menyadarinya.
Tentukan ukuran dari kapasitas database
Mulailah dari connection budget yang aman. Sisakan kapasitas untuk migration, admin, background worker, replica, dan monitoring. Bagi sisanya untuk service serta jumlah replica maksimalnya. Hasilnya adalah plafon, bukan target yang harus dipenuhi.
Pada aplikasi web biasa, pool kecil—sering kali satu digit hingga beberapa puluh koneksi per process—sudah cukup jika query pendek dan index sehat. Ukur pool wait time, query latency, serta utilization database sebelum memperbesarnya. Jika request menunggu koneksi saat database idle, pool mungkin terlalu kecil atau ada connection leak. Jika database sudah jenuh, pool lebih besar biasanya memperburuk waktu respons.
Lepaskan koneksi secepatnya
Gunakan pola driver yang menjamin koneksi dilepas bahkan saat error. Jangan menahan transaction ketika memanggil API eksternal, upload file, atau menunggu input pengguna.
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("UPDATE inventory SET stock = stock - 1 WHERE id = $1", [id]);
await client.query("COMMIT");
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
Bagian finally adalah kuncinya. Connection leak sering baru terlihat beberapa menit kemudian sebagai timeout acak saat pool diam-diam habis.
Timeout dan backpressure
Tetapkan acquire timeout yang singkat dan jelas. Request yang tidak mendapat koneksi harus gagal secara terprediksi atau melepaskan pekerjaan, bukan menunggu sampai semua worker aplikasi macet. Atur statement serta transaction timeout di database juga. Keduanya membatasi dampak query plan tak terduga dan lock contention.
Saturasi pool adalah sinyal untuk memeriksa seluruh jalur: query lambat, index kurang, transaction panjang, lonjakan traffic, atau masalah database. Retry hanya operasi idempotent, gunakan exponential backoff dengan jitter, dan batasi retry agar kegagalan tidak berubah menjadi retry storm.
Serverless dan monitoring
Di serverless, setiap invocation concurrent berpotensi membuat pool. Pakai database proxy atau connection broker bila tersedia, jaga client pool sangat kecil, dan gunakan kembali client di luar handler bila runtime mengizinkan. Pantau koneksi aktif, idle, waiting, timeout, query duration, lock wait, serta error rate. Antrean pool menunjukkan apakah request lambat sebelum query dimulai atau ketika query berjalan.
Checklist
- Hitung batas pool dari kapasitas database dan replica maksimal.
- Lepaskan setiap koneksi, dan buat transaction sesingkat mungkin.
- Konfigurasikan acquire, statement, dan transaction timeout.
- Gunakan proxy atau pool kecil untuk concurrency serverless yang meledak.
- Periksa query lambat dan lock sebelum menaikkan ukuran pool.
Kesimpulan
Connection pooling adalah bentuk backpressure. Pool yang dibatasi dan dapat diobservasi membuat aplikasi memakai database secara efisien sambil menjaga overload tetap terlihat. Tujuannya bukan menyembunyikan database lambat, melainkan mencegah database lambat menjatuhkan sistem lain.
Artikel Terkait
Lanjutkan membaca topik yang masih satu konteks.
Database Indexing Strategy: B-Trees, Hash Indexes, dan Lainnya
Pelajari cara memilih, memvalidasi, dan merawat database index tanpa memperlambat write atau menebak-nebak performa.
NoSQL vs Relational: Memilih Database yang Tepat untuk Proyek Kamu
Kerangka praktis untuk memilih database relational atau NoSQL berdasarkan bentuk data, query, konsistensi, dan kebutuhan operasional.
Panduan GraphQL API: Schema, Query, dan Mutation
Pelajari dasar GraphQL API lewat schema, query, mutation, resolver, error handling, dan pola praktis untuk data aplikasi.
Redis untuk Backend: Cache, Session, dan Pub/Sub
Panduan praktis menggunakan Redis untuk cache, session, dan Pub/Sub secara aman, termasuk TTL, eviction, persistence, serta trade-off operasional.