Disk adalah sumber daya yang tidak bertambah sendiri, dan server MongoDB tidak akan berhenti menulis hanya karena disk hampir penuh — ia hanya gagal dengan cara yang paling menyakitkan. Tugas kita sebagai admin adalah membaca arah pertumbuhan data sebelum batas tercapai: memahami isi direktori dbPath, mengartikan angka dataSize versus storageSize, dan tahu kapan kompresi serta compact layak dijalankan. Chapter ini membedah semuanya dengan angka asli dari server latihan.

Peta materi chapter ini:

  • Isi direktori dbPath dan arti tiap jenis berkas.
  • db.stats() dan db.coll.stats() sebagai sumber ukuran.
  • Kompresi blok WiredTiger: snappy bawaan dan zstd opsional.
  • compact untuk mengembalikan ruang disk.

Isi Direktori dbPath #

Semua data server latihan kita hidup di /home/z/my-project/mongo-data (produksi lazimnya /var/lib/mongodb). Mari kita intip isinya:

bash
ls -lh /home/z/my-project/mongo-data | head -n 12

Output yang Dihasilkan:

text
total 62M
-rw------- 1 z z   50 Oct 17 12:47 WiredTiger
-rw------- 1 z z   21 Oct 17 12:47 WiredTiger.lock
-rw------- 1 z z  1.6K Oct 17 20:08 WiredTiger.turtle
-rw------- 1 z z  1.4M Oct 17 20:08 WiredTiger.wt
-rw------- 1 z z   40K Oct 17 20:08 WiredTigerHS.wt
-rw------- 1 z z   76K Oct 17 20:08 _mdb_catalog.wt
drwx------ 3 z z   4.0K Oct 17 13:05 _tmp
-rw------- 1 z z   36K Oct 17 15:10 collection-035fe75a-752b-4ba8-98c4-c63c93bf163c.wt
-rw------- 1 z z   36K Oct 17 17:32 collection-03ce6fec-2a7d-4510-826b-e9292f64f1d6.wt
-rw------- 1 z z   36K Oct 17 17:35 collection-0b780888-ef26-451a-8211-a933f1edcb05.wt
-rw------- 1 z z   36K Oct 17 17:39 collection-0be3951c-d2d-44cc-b2-98c4-c63c93bf7055f.wt
...

Satu collection sama sekali bukan satu berkas tunggal — polanya seperti ini:

Pola berkasIsinya
collection-<uuid>.wtData satu collection, satu berkas per collection
index-<uuid>.wtData satu index, satu berkas per index
_mdb_catalog.wtKatalog: pemetaan namespace → UUID berkas
WiredTiger.wtMetadata storage engine
WiredTigerHS.wtHistory store untuk snapshot MVCC
WiredTiger.lock + WiredTigerKunci proses dan identitas dasar
journal/Write-ahead log sebelum dipermanenkan

Saat ini direktori itu berisi 124 berkas collection-*.wt dan 190 berkas index-*.wt — bukti nyata bahwa jumlah berkas tumbuh mengikuti jumlah collection dan index, bukan jumlah document. Konsekuensinya penting untuk kapasitas: ribuan collection berarti ribuan berkas kecil, dan ulimit file descriptor (chapter Proses Server Database) ikut bermain.

Membaca Ukuran dengan db.stats() #

Dari sisi mongosh, potret ukuran sebuah database dilihat lewat db.stats(). Siapkan database latihan kecil lebih dulu:

js
use latihan_admin
db.dropDatabase()
db.pembelian.insertMany([
  { _id: 1, pelanggan: "Budi", total: 150000 },
  { _id: 2, pelanggan: "Siti", total: 275000 },
  { _id: 3, pelanggan: "Dewi", total: 98000 }
])

Output yang Dihasilkan:

text
switched to db latihan_admin
{ ok: 1, dropped: 'latihan_admin' }
{ acknowledged: true, insertedIds: { '0': 1, '1': 2, '2': 3 } }

Kemudian baca statistiknya:

js
db.stats()

Output yang Dihasilkan:

text
{
  db: 'latihan_admin',
  collections: Long('1'),
  views: Long('0'),
  objects: Long('3'),
  avgObjSize: 45,
  dataSize: 135,
  storageSize: 4096,
  indexes: Long('1'),
  indexSize: 4096,
  totalSize: 8192,
  scaleFactor: Long('1'),
  fsUsedSize: 2659106816,
  fsTotalSize: 10531131392,
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1792267827, i: 5 }),
    signature: {
      hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
      keyId: Long('0')
    }
  },
  operationTime: Timestamp({ t: 1792267827, i: 5 })
}

Empat angka ini yang perlu dibaca berkala:

FieldArtiCatatan
dataSizeTotal byte BSON semua document — sebelum kompresiAngka logis, bukan pemakaian disk
storageSizeRuang disk nyata untuk data collectionSelalu kelipatan halaman 4 KB
indexSizeRuang disk untuk semua indextotalSize = storageSize + indexSize
fsUsedSize/fsTotalSizePemakaian disk filesystem tempat dbPath beradaAngka kapasitas sebenarnya

Perhatikan keanehan yang justru penting: dataSize hanya 135 byte tetapi storageSize 4096 byte. WiredTiger mengalokasikan ruang dalam satuan halaman 4 KB, sehingga collection mungil selalu tampak “lebih besar di disk” — pembulatan ke atas ke satu halaman penuh. Bandingkan angka-angka ini antar waktu untuk melihat tren, jangan membaca satu snapshot secara terpisah.

Kompresi WiredTiger dalam Praktik #

Semua berkas data WiredTiger dikompresi blok demi blok. Kompresor bawaannya adalah snappy — bisa diverifikasi langsung dari metadata sebuah collection:

js
const teks = "Laporan penjualan triwulan ini mencakup wilayah Jakarta dan sekitarnya. ".repeat(80)
db.laporan.insertMany([
  { _id: 1, isi: teks },
  { _id: 2, isi: teks },
  { _id: 3, isi: teks }
])
db.laporan.stats().wiredTiger.creationString.match(/block_compressor=\w+/)[0]

Output yang Dihasilkan:

text
{ acknowledged: true, insertedIds: { '0': 1, '1': 2, '2': 3 } }
block_compressor=snappy

String block_compressor=snappy dikonfirmasi aktif pada collection itu. Sekarang bandingkan ukuran logis vs fisiknya:

js
const s = db.laporan.stats()
[ s.ns, s.count, s.size, s.storageSize, s.totalIndexSize ]

Output yang Dihasilkan:

text
[ 'latihan_admin.laporan', 3, 17352, 4096, 4096 ]

Tiga document berisi teks berulang sebesar 17.352 byte BSON hanya memakan 4.096 byte di disk — teks yang mirip adalah kasus terbaik kompresi. Pada data dunia nyata, rasio 2–4 kali adalah harapan yang sehat. Kompresor alternatif zstd bisa dipilih per collection saat pembuatan:

js
db.createCollection("arsip", { storageEngine: { wiredTiger: { configString: "block_compressor=zstd" } } })
db.arsip.insertMany([{ _id: 1, isi: teks }, { _id: 2, isi: teks }, { _id: 3, isi: teks }])
db.arsip.stats().wiredTiger.creationString.match(/block_compressor=\w+/)[0]

Output yang Dihasilkan:

text
{ ok: 1 }
{ acknowledged: true, insertedIds: { '0': 1, '1': 2, '2': 3 } }
block_compressor=zstd

zstd umumnya menghasilkan rasio lebih baik dengan CPU sedikit lebih tinggi — pas untuk data arsip yang jarang dibaca. Selain kompresi blok, WiredTiger juga mengompresi prefiks key pada index secara bawaan, itulah sebabnya index atas field bernilai mirip hemat ruang.

compact: Mengembalikan Ruang Disk #

Menghapus document tidak serta-merta mengecilkan berkas .wt — WiredTiger menandai ruang kosong agar bisa dipakai ulang, tetapi mempertahankan ukuran berkasnya. Perintah compact menulis ulang collection untuk mengembalikan ruang itu ke sistem operasi:

js
// mdtest: skip
db.laporan.compact()

Sejak MongoDB 4.4, compact tidak lagi memblokir baca/tulis pada collection target, tetap saja perintah ini memakan CPU dan I/O sehingga dijadwalkan di jendela sepi. Pada replica set, compact tidak direplikasi — jalankan terpisah di tiap anggota, mulai dari secondary, dan biarkan primary terakhir. Kandidat terbaik untuk compact adalah collection yang barusan kehilangan porsi besar datanya: purge batch, TTL besar-besaran, atau migrasi schema.

Rangkuman #

  • dbPath berisi satu berkas per collection dan per index (bernama UUID), katalog _mdb_catalog.wt, dan direktori journal/.
  • dataSize adalah ukuran BSON sebelum kompresi; storageSize dan indexSize adalah pemakaian disk nyata dalam kelipatan halaman 4 KB.
  • Kompresor blok bawaan snappy; zstd bisa dipilih per collection lewat configString saat createCollection.
  • compact menulis ulang collection untuk mengembalikan ruang kosong ke OS — tidak memblokir CRUD sejak 4.4, dijadwalkan di jendela sepi, dijalankan per anggota replica set.