Aplikasi web melayani ratusan request setiap detik, dan setiap request yang menyentuh database butuh koneksi. Membuka koneksi TCP baru untuk tiap request berarti membayar handshake, negosiasi TLS, dan autentikasi berulang-ulang — belum lagi beban di sisi server, yang menyediakan thread dan hingga 1 MB RAM untuk setiap koneksi yang diterima. Connection pool milik driver menyelesaikan ini dengan menyimpan koneksi terbuka yang bisa dipakai ulang. Chapter ini membedah opsi-opsi pool, pola pemakaian yang benar, dan cara mengamati jumlah koneksi dari sisi server.
Peta materi Chapter ini:
- Anatomi pool driver:
maxPoolSize,minPoolSize,maxIdleTimeMS,waitQueueTimeoutMS. - Pola satu
MongoClientuntuk seluruh aplikasi (singleton). - Mengamati koneksi lewat
db.serverStatus().connections. - Batas sisi server dan perencanaan kapasitas pool.
Pool di Sisi Driver #
Pool hidup di dalam driver, bukan di server. Ketika MongoClient dibuat, driver menyiapkan koneksi ke server dan menyimpannya di pool; thread aplikasi meminjam koneksi saat menjalankan operasi lalu mengembalikannya begitu selesai. Koneksi yang kembali tidak ditutup — ia menjadi idle dan siap dipinjam thread berikutnya. Jika semua koneksi sedang dipakai, operasi berikutnya masuk wait queue sampai ada yang dikembalikan atau sampai batas waktu tunggu terlampaui.
| Opsi | Peran | Default |
|---|---|---|
maxPoolSize | Jumlah maksimum koneksi yang dibuka pool; permintaan di atasnya masuk wait queue | 100 |
minPoolSize | Jumlah minimum koneksi yang dijaga tetap terbuka, siap untuk lonjakan trafik | 0 |
maxIdleTimeMS | Lama maksimum koneksi idle boleh disimpan sebelum ditutup | bervariasi per driver |
waitQueueTimeoutMS | Lama maksimum sebuah operasi menunggu di antrean; 0 berarti tanpa batas | 0 |
maxConnecting | Jumlah koneksi yang boleh sedang dibuka bersamaan | 2 |
Opsi-opsi ini ditulis langsung di connection string atau saat pembuatan client. Untuk driver Node.js, konfigurasinya terlihat seperti ini:
// mdtest: skip — ilustrasi driver Node.js (driver tidak terpasang di lingkungan latihan)
const { MongoClient } = require("mongodb")
// SATU client level modul: pool dibuat sekali, dipakai semua request
const client = new MongoClient("mongodb://127.0.0.1:27017/?directConnection=true", {
maxPoolSize: 50,
minPoolSize: 5,
maxIdleTimeMS: 30000,
waitQueueTimeoutMS: 5000
})
async function catatPenjualan(transaksi) {
await client.db("toko").collection("penjualan").insertOne(transaksi)
}Baris pentingnya: client dibuat sekali di level modul sehingga seluruh request berbagi pool yang sama, maxPoolSize: 50 membatasi jumlah koneksi maksimum ke 50, dan waitQueueTimeoutMS: 5000 membuat operasi gagal cepat dengan galat setelah 5 detik mengantre alih-alih menggantung tanpa batas.
Mengamati Koneksi dari Sisi Server #
Apa pun konfigurasi di sisi driver, kebenaran akhirnya ada di angka server. db.serverStatus().connections melaporkan kondisi koneksi saat ini:
use latihan_perf
const c = db.serverStatus().connections
print("current :", c.current)
print("available :", c.available)
print("totalCreated :", c.totalCreated)
print("current + available =", c.current + c.available)Output yang Dihasilkan:
switched to db latihan_perf
current : 5
available : 404
totalCreated : 6678
current + available = 409Empat angka ini masing-masing bercerita: current adalah koneksi yang sedang terbuka (termasuk sesi mongosh kita sendiri dan koneksi monitoring antar anggota replica set), available adalah slot yang masih bisa diterima, totalCreated menghitung seluruh koneksi yang pernah dibuat sejak server menyala — angka kumulatif yang terus naik walau koneksi sudah ditutup, dan lonjakan cepatnya adalah petunjuk adanya client yang membuat koneksi terus-menerus. Penjumlahan current + available adalah batas efektif server kita.
Batas itu sendiri diatur net.maxIncomingConnections. Di Linux sejak MongoDB 8.1 nilainya default ke (RLIMIT_NOFILE / 2) × 0.8 — sekitar 409 pada mesin lab kita dengan batas file descriptor 1024. Perilaku pool terlihat langsung saat kita menjalankan beberapa proses klien sekaligus:
U="mongodb://127.0.0.1:27017/?directConnection=true"
mongosh --quiet --eval 'const c = db.serverStatus().connections; print("current:", c.current, "| available:", c.available)' "$U"
for i in 1 2 3; do mongosh --quiet --eval 'sleep(6000)' "$U" >/dev/null 2>&1 & done
sleep 2
mongosh --quiet --eval 'const c = db.serverStatus().connections; print("current:", c.current, "| available:", c.available)' "$U"
wait
mongosh --quiet --eval 'const c = db.serverStatus().connections; print("current:", c.current, "| available:", c.available)' "$U"Output yang Dihasilkan:
current: 6 | available: 403
current: 18 | available: 391
current: 6 | available: 403Tiga proses mongosh paralel menaikkan current dari 6 ke 18 — setiap proses klien memegang beberapa koneksi sekaligus (satu untuk operasi, sisanya untuk monitoring topologi), dan available berkurang persis sebanyak kenaikannya. Begitu ketiga proses selesai, angka kembali seperti semula: koneksi ditutup, slot tersedia lagi. Inilah siklus hidup yang dikelola pool secara otomatis di dalam aplikasi.
Perencanaan Kapasitas Pool #
Kebutuhan koneksi total aplikasi adalah jumlah instance dikalikan maxPoolSize masing-masing — dan angka ini harus muat di bawah batas server, menyisakan ruang untuk mongosh, monitoring, dan anggota replica set. Kita bisa menghitungnya langsung dengan angka nyata dari server:
const c = db.serverStatus().connections
const batasEfektif = c.current + c.available
print("batas efektif server:", batasEfektif, "koneksi")
for (const instansi of [4, 8]) {
const kebutuhan = instansi * 100
const status = kebutuhan <= batasEfektif ? "aman" : "melebihi batas"
print(`${instansi} instansi x maxPoolSize 100 = ${kebutuhan} koneksi -> ${status}`)
}Output yang Dihasilkan:
batas efektif server: 409 koneksi
4 instansi x maxPoolSize 100 = 400 koneksi -> aman
8 instansi x maxPoolSize 100 = 800 koneksi -> melebihi batasEmpat instance aplikasi dengan pool default masih muat; delapan instance tidak. Skala arah mana pun punya gejalanya masing-masing:
| Gejala | Penyebab umum | Perbaikan |
|---|---|---|
current menempel batas, koneksi ditolak | Terlalu banyak instance atau pool terlalu besar | Turunkan maxPoolSize, tambah RAM server |
| Operasi mengantre, latensi naik walau CPU sepi | Pool terlalu kecil untuk concurrency aplikasi | Naikkan maxPoolSize, cek waitQueueTimeoutMS |
totalCreated meroket terus | Client baru dibuat per request | Perbaiki pola singleton client |
| Burst pagi hari gagal koneksi | Pool kosong saat diam, koneksi dibuka terlambat | Set minPoolSize di atas nol |
Aturan praktisnya: mulai dari default (maxPoolSize 100), ukur current dan antrean pada beban puncak, lalu sesuaikan bertahap. Pool yang sehat adalah yang cukup besar untuk concurrency asli aplikasi dan cukup kecil untuk tidak membelanjakan memori server percuma.
Rangkuman #
- Pool driver menyimpan koneksi terbuka yang dipinjam dan dikembalikan;
maxPoolSize(default 100) membatasi ukurannya,waitQueueTimeoutMSmengatur lamanya operasi mengantre. - Satu
MongoClientper aplikasi — client di level modul dengan pool yang dibagikan; membuat client per request menimbulkan gelombang koneksi ke server. db.serverStatus().connectionsmenunjukkancurrent,available, dantotalCreateddari sudut pandang server;current + availableadalah batas efektifnet.maxIncomingConnections.- Kebutuhan koneksi = jumlah instance ×
maxPoolSize; angka ini harus muat di bawah batas server bersama koneksi monitoring dan administratif.