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 MongoClient untuk 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.

OpsiPeranDefault
maxPoolSizeJumlah maksimum koneksi yang dibuka pool; permintaan di atasnya masuk wait queue100
minPoolSizeJumlah minimum koneksi yang dijaga tetap terbuka, siap untuk lonjakan trafik0
maxIdleTimeMSLama maksimum koneksi idle boleh disimpan sebelum ditutupbervariasi per driver
waitQueueTimeoutMSLama maksimum sebuah operasi menunggu di antrean; 0 berarti tanpa batas0
maxConnectingJumlah koneksi yang boleh sedang dibuka bersamaan2

Opsi-opsi ini ditulis langsung di connection string atau saat pembuatan client. Untuk driver Node.js, konfigurasinya terlihat seperti ini:

js
// 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:

js
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:

text
switched to db latihan_perf

current      : 5

available    : 404

totalCreated : 6678

current + available = 409

Empat 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:

bash
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:

text
current: 6 | available: 403
current: 18 | available: 391
current: 6 | available: 403

Tiga 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:

js
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:

text
batas efektif server: 409 koneksi

4 instansi x maxPoolSize 100 = 400 koneksi -> aman

8 instansi x maxPoolSize 100 = 800 koneksi -> melebihi batas

Empat instance aplikasi dengan pool default masih muat; delapan instance tidak. Skala arah mana pun punya gejalanya masing-masing:

GejalaPenyebab umumPerbaikan
current menempel batas, koneksi ditolakTerlalu banyak instance atau pool terlalu besarTurunkan maxPoolSize, tambah RAM server
Operasi mengantre, latensi naik walau CPU sepiPool terlalu kecil untuk concurrency aplikasiNaikkan maxPoolSize, cek waitQueueTimeoutMS
totalCreated meroket terusClient baru dibuat per requestPerbaiki pola singleton client
Burst pagi hari gagal koneksiPool kosong saat diam, koneksi dibuka terlambatSet 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, waitQueueTimeoutMS mengatur lamanya operasi mengantre.
  • Satu MongoClient per aplikasi — client di level modul dengan pool yang dibagikan; membuat client per request menimbulkan gelombang koneksi ke server.
  • db.serverStatus().connections menunjukkan current, available, dan totalCreated dari sudut pandang server; current + available adalah batas efektif net.maxIncomingConnections.
  • Kebutuhan koneksi = jumlah instance × maxPoolSize; angka ini harus muat di bawah batas server bersama koneksi monitoring dan administratif.