mongodump membaca data lewat protokol database — sempurna untuk data kecil, tetapi membaca satu terabyte document demi document memakan berjam-jam. Ada jalur yang jauh lebih cepat: biarkan sistem operasi yang menyalin. Filesystem snapshot mengambil gambar seluruh volume disk tempat data MongoDB berada dalam hitungan detik, tanpa peduli berapa banyak document di dalamnya. Kecepatan itu datang dengan dua syarat konsistensi yang harus dipenuhi, dan chapter ini membedah keduanya — lalu membuktikannya pada server latihan kita.

Peta materi Chapter ini:

  • Mekanisme snapshot level blok: pointer dan copy-on-write.
  • Dua syarat konsistensi: journal aktif, dan journal satu volume dengan data — dibuktikan lewat serverStatus().
  • Aturan mutlak: seluruh dbPath harus ikut tersalin.
  • Prosedur restore: menyalin balik dan catatan mongod.lock.

Menyalin di Level Blok #

Snapshot bekerja dengan membuat pointer antara data yang hidup dan volume snapshot khusus — mekanisme yang setara dengan hard link. Saat data asli berubah, teknik copy-on-write menyalin blok lama ke area snapshot lebih dulu, sehingga snapshot tetap menunjuk ke keadaan awal. Konsekuensinya efisien: snapshot hanya menyimpan data yang berubah, dan pembuatannya selesai dalam hitungan detik walau volumenya ratusan gigabyte.

Kemampuan ini bukan fitur MongoDB, melainkan fitur volume manager dan penyimpanan di bawahnya — dua contoh paling umum:

bash
  # Linux: snapshot LVM (contoh dari dokumentasi resmi MongoDB)
  # sesuaikan nama volume group dan ukuran dengan sistem Anda
lvcreate --size 100M --snapshot --name mdb-snap01 /dev/vg0/mongodb

  # AWS: snapshot volume EBS yang menampung dbPath
aws ec2 create-snapshot --volume-id vol-0123456789abcdef0 \
  --description "backup mongodb mingguan"

Ukuran --size 100M pada contoh LVM bukan ukuran data, melainkan ruang cadangan untuk perubahan selama snapshot masih hidup — bila habis sebelum arsip disalin, snapshot menjadi tidak terpakai. Blok perintah di atas ditulis sebagai referensi (tidak dieksekusi di lingkungan latihan); keluaran asli server latihan kita justru akan kita lihat pada bagian dbPath di bawah.

Dua Syarat Konsistensi #

Sebuah snapshot hanya berguna bila berkas yang tersalin membentuk keadaan database yang sah. Untuk WiredTiger, berkas data mencerminkan keadaan konsisten per checkpoint terakhir — yang terjadi setiap 2 GB data baru atau setiap satu menit. Tulisan yang lebih baru dari checkpoint terakhir hidup di journal: server membilas journal ke disk setiap sekitar 100 milidetik.

Dari sini lahir aturan pertama dari dokumentasi resmi: untuk mendapatkan snapshot yang benar dari mongod yang sedang berjalan, journaling harus aktif dan journal harus berada di volume logis yang sama dengan berkas data. Snapshot yang menyertakan journal otomatis menangkap seluruh tulisan yang sudah diterima database hingga sepersekian detik sebelumnya. Mari kita buktikan bahwa journal memang menerima catatan terus-menerus — dua penghitung WiredTiger kita bandingkan sebelum dan sesudah satu insert:

js
use latihan_backup
const s1 = db.serverStatus().wiredTiger.log
db.buku.insertOne({ judul: "Bumi", harga: 89000, stok: 20 })
const s2 = db.serverStatus().wiredTiger.log
print("log write operations : " + s1["log write operations"] + " -> " + s2["log write operations"])
print("log sync operations  : " + s1["log sync operations"] + " -> " + s2["log sync operations"])

Output yang Dihasilkan:

text
switched to db latihan_backup

{
  acknowledged: true,
  insertedId: ObjectId('6ad3cacd3aa3ea6b20460881')
}

log write operations : 37649 -> 37651

log sync operations  : 10845 -> 10846

Dua baris terakhir adalah buktinya. Penghitung log write operations (catatan yang ditulis ke journal) bertambah untuk satu insertOne — beserta pembaruan internal WiredTiger, semuanya tercatat di journal sebelum mendarat di berkas data. Penghitung log sync operations (pembilasan journal ke disk) juga bertambah; server melakukannya rutin setiap sekitar 100 milidetik, sehingga snapshot yang menyertakan journal menangkap semua tulisan yang diterima hingga sepersekian detik sebelumnya. Bila journal dibuang dari snapshot, tulisan-tulisan “muda” inilah yang hilang dan hasil restore bisa tidak konsisten. (Nilai penghitung akan berbeda di setiap eksekusi — yang penting adalah kenaikannya.)

Lalu bagaimana bila journal terpaksa berada di volume terpisah? Aturan keduanya: kunci database agar tidak ada tulisan selama snapshot berlangsung — bilas semua tulisan ke disk dengan db.fsyncLock(), ambil snapshot kedua volume, lalu buka kuncinya:

js
// mdtest: skip — mengunci server bersama; jangan dijalankan di lingkungan latihan
// db.fsyncLock()   // bilas + kunci: tulisan baru menunggu
// ... ambil snapshot semua volume di sini ...
// db.fsyncUnlock() // buka kunci

Pada replica set, alternatif yang lebih ramah adalah mengambil snapshot dari node secondary tersembunyi — primary tidak pernah terganggu.

Seluruh dbPath Harus Ikut #

Syarat berikutnya sederhana namun sering dilanggar: snapshot harus memuat seluruh isi dbPath, bukan hanya berkas yang tampak besar. Lokasi dbPath bisa kita tanyakan langsung ke server:

js
db.adminCommand({ getCmdLineOpts: 1 }).parsed.storage

Output yang Dihasilkan:

text
{
  dbPath: '/home/z/my-project/mongo-data',
  wiredTiger: { engineConfig: { cacheSizeGB: 0.25 } }
}

Server latihan kita menyimpan data di /home/z/my-project/mongo-data. Isinya bisa kita ringkas dengan mengelompokkan berkas menurut polanya (server ini menampung ratusan berkas sisa latihan):

bash
ls /home/z/my-project/mongo-data | sed -E 's/-[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\.wt/-UUID.wt/' | sort | uniq -c | sort -rn

Output yang Dihasilkan:

text
    182 index-UUID.wt
    119 collection-UUID.wt
      1 storage.bson
      1 sizeStorer.wt
      1 mongod.log
      1 mongod.lock
      1 mongod-stdout.log
      1 journal
      1 diagnostic.data
      1 _tmp
      1 _mdb_catalog.wt
      1 WiredTigerHS.wt
      1 WiredTiger.wt
      1 WiredTiger.turtle
      1 WiredTiger.lock
      1 WiredTiger

Setiap jenis berkas punya peran — dan semuanya dibutuhkan agar snapshot bisa hidup kembali:

Berkas/direktoriPeran
collection-*.wt, index-*.wtData dan index per collection (satu berkas per object)
journal/Log tulisan pracheckpoint — kunci konsistensi
_mdb_catalog.wtKatalog: pemetaan namespace ke berkas
WiredTiger.wt, WiredTiger.turtle, WiredTigerMetadata inti storage engine
sizeStorer.wt, storage.bsonStatistik ukuran dan metadata versi
mongod.lockBerkas kunci proses (dibaca ulang saat startup)

Restore: Salin Balik #

Memulihkan snapshot berarti menempatkan kembali salinan itu ke volume (atau volume baru) dan mengarahkan mongod ke dbPath tersebut — mongod akan membaca metadata WiredTiger dan melakukan pemulihan journal bila ada tulisan pracheckpoint yang belum masuk checkpoint. Karena berkas mongod.lock hasil salinan berstatus usang, dokumentasi menyarankan menghapusnya agar startup tidak dianggap tidak bersih. Dua pekerjaan tambahan menyertai: snapshot wajib diarsipkan keluar dari sistem penyimpanan yang sama (salinan dd terkompresi atau replikasi ke host lain), dan untuk sharded cluster, balancer dimatikan dulu lalu semua shard beserta config server di-snapshot hampir bersamaan.

Perbandingan lengkapnya dengan metode lain dirangkum di sini:

AspekFilesystem snapshotmongodump
Kecepatan backupDetik-menit (copy-on-write)Berjam-jam pada data besar
Kecepatan restoreCepat: salin balik berkasLambat: baca BSON + bangun ulang index
Ukuran hasilSebesar volume (termasuk index, padding, fragmentasi)Lebih kecil (hingga 2× lebih hemat)
Backup incrementalTergantung platform penyimpananTidak ada
PortabilitasTerikat pada versi berkas dan OSBuka di MongoDB versi mana pun
KonsistensiJournal satu volume, atau fsyncLock--oplog pada replica set

Rangkuman #

  • Snapshot level blok menyalin pointer, bukan data — pembuatannya cepat dan hanya menyimpan perubahan (copy-on-write).
  • Konsistensi mongod yang berjalan menuntut journal aktif di volume yang sama dengan data; journal dibilas tiap ±100 ms, terbukti dari penghitung log records written yang bertambah setelah satu insert.
  • Journal di volume terpisah memaksa db.fsyncLock() sebelum snapshot dan db.fsyncUnlock() setelahnya.
  • Seluruh isi dbPath — data, index, katalog, metadata WiredTiger, journal — wajib tersalin serentak; restore berarti menyalin balik lalu menghapus mongod.lock yang usang.
  • Lebih cepat dari dump untuk data besar, tetapi hasilnya lebih besar, tidak portabel, dan tanpa incremental bawaan.