Backup adalah salinan database yang disimpan terpisah, supaya data bisa dikembalikan (restore atau recovery) setelah hilang atau rusak: disk mati, server dihapus, atau seseorang menjalankan DELETE tanpa WHERE. Bayangin buku kas Kedai Senja difotokopi setiap tengah malam. Jam 14:30 buku aslinya ketumpahan kopi. Kamu bisa menyalin ulang dari fotokopi semalam, tapi semua transaksi sejak tengah malam hilang, kecuali kamu juga menyimpan struk-struknya. Fotokopi itu full backup, dan tumpukan struk itu log perubahan.
🧪 Tebakan cepat: Kedai Senja di-backup penuh setiap pukul 00:00. Hari ini sampai pukul 14:29 ada 7 pesanan, 4 di antaranya masuk setelah tengah malam. Pukul 14:30 seseorang menjalankan
DELETE FROM orders;(lupaWHERE). Setelah restore dari backup 00:00, berapa pesanan yang kembali? Tebak dulu, jawabannya ada di bagian "RPO dan RTO".
Satu hari di Kedai Senja
Lab di halaman ini memutar hari ini di SQLite sungguhan:
| Jam | Kejadian |
|---|---|
| 00:00 | full backup: 3 pelanggan, 4 produk, 3 pesanan (#1 sampai #3) |
| 07:20 | pesanan #4: Andi, 1 Teh Tarik |
| 09:15 | pesanan #5: Siti, 2 Kopi Susu Aren |
| 11:40 | pesanan #6: Budi, 1 Roti Bakar |
| 13:05 | harga Roti Bakar naik dari 20.000 jadi 22.000 |
| 14:10 | pesanan #7: Budi, 1 Kopi Susu |
| 14:30 | DELETE FROM orders; semua pesanan hilang |
RPO dan RTO
Dua angka yang harus kamu sepakati dengan pemilik bisnis sebelum bencana:
- RPO (Recovery Point Objective): berapa banyak data terakhir yang boleh hilang, diukur dalam waktu ke belakang dari bencana. "RPO 1 jam" artinya paling banyak 1 jam terakhir boleh hilang.
- RTO (Recovery Time Objective): berapa lama aplikasi boleh mati sampai pulih. "RTO 30 menit" artinya restore harus selesai dalam 30 menit.
Backup penuh cuma pukul 00:00 berarti titik pulihnya 00:00. Yang kembali cuma 3 pesanan (#1 sampai #3). Pesanan #4 sampai #7 dan kenaikan harga Roti Bakar hilang: data 14 jam 30 menit lenyap. Itu jawaban tebakannya. Backup harian berarti RPO sampai 24 jam, dan untuk toko online itu biasanya terlalu besar.
Full, incremental, differential
Supaya RPO lebih kecil, backup harus lebih sering. Menyalin seluruh database setiap jam itu berat, jadi ada tiga jenis:
- Full backup: menyalin seluruh database. Paling lengkap, paling besar, paling lama.
- Incremental backup: cuma perubahan sejak backup terakhir apa pun (full atau incremental sebelumnya).
- Differential backup: semua perubahan sejak full backup terakhir.
Di Lab, full pukul 00:00 lalu backup kecil pukul 04:00, 08:00 dan 12:00:
| Backup | Incremental berisi | Differential berisi |
|---|---|---|
| 04:00 | 0 perubahan | 0 perubahan |
| 08:00 | #4 | #4 |
| 12:00 | #5, #6 | #4, #5, #6 |
- Restore dengan incremental butuh full + semua incremental berurutan: 4 file. File kecil, tapi satu saja rusak, rantainya putus.
- Restore dengan differential cukup full + differential terakhir: 2 file. Filenya makin besar seiring hari, tapi restore-nya lebih cepat.
- Dua-duanya kembali ke kondisi 12:00: 6 pesanan, harga Roti Bakar masih 20.000. Data yang hilang 2 jam 30 menit (kenaikan harga dan pesanan #7).
PITR: kembali ke detik sebelum bencana
PostgreSQL menulis setiap perubahan ke WAL (Write-Ahead Log) sebelum menerapkannya ke tabel. Kalau file WAL itu terus diarsip, kamu bisa melakukan PITR (Point-in-Time Recovery): pasang base backup, lalu putar ulang WAL sampai detik yang kamu pilih.
# postgresql.conf di server yang di-restore (PostgreSQL 12 ke atas)
restore_command = 'cp /backup/wal/%f %p'
recovery_target_time = '2026-10-08 14:29:59'
# lalu buat file kosong recovery.signal di folder data, dan nyalakan server
restore_commandmemberi tahu PostgreSQL cara mengambil file WAL dari arsip.recovery_target_timeberhenti tepat sebelumDELETEpukul 14:30.- Hasilnya di Lab: 7 pesanan kembali dan harga Roti Bakar 22.000. Data yang hilang cuma hitungan detik.
Alat PostgreSQL: pg_dump dan pg_basebackup
# logical backup: file SQL berisi CREATE TABLE dan semua datanya
pg_dump -h localhost -U postgres mydb > backup.sql
# restore-nya: jalankan file SQL itu
psql mydb < backup.sql
# physical backup: salinan file data PostgreSQL apa adanya
pg_basebackup -D /backup/base -Ft -z -P
# arsip WAL terus-menerus (postgresql.conf), syarat PITR
archive_mode = on
archive_command = 'cp %p /backup/wal/%f'
pg_dumpmenghasilkan logical backup: perintah SQL untuk membangun ulang database. Gampang dibaca dan dipindah, cocok untuk database kecil. Restore-nya memasukkan ulang semua baris dan membangun ulang index, jadi untuk database besar restore bisa berjam-jam (RTO panjang). Lab ini memakai SQLite, dan file backup-nya hasil ekspor SQL ala.dumpmilik sqlite3, setarapg_dump.pg_basebackupmenghasilkan physical backup: salinan file data. Restore-nya tinggal menyalin balik, jauh lebih cepat untuk database besar.pg_basebackup+ WAL archiving memberi PITR: RPO hitungan detik.
Cara memilih, persis seperti di latihan:
| Ukuran database | Boleh lama down saat restore? | Pilihan |
|---|---|---|
| kecil (di bawah 1 GB) | apa saja | pg_dump |
| sedang (1 sampai 100 GB) | boleh | pg_dump |
| sedang (1 sampai 100 GB) | tidak boleh | pg_basebackup |
| besar (di atas 100 GB) | apa saja | pg_basebackup + WAL archiving |
Backup yang gak pernah dites bukan backup
Bayangin job backup yang salah setting: perintahnya pg_dump --schema-only, jadi filenya cuma berisi CREATE TABLE tanpa satu baris data pun. File muncul setiap malam, job-nya "sukses", dan gak ada yang curiga sampai hari bencana. Satu-satunya cara tahu adalah restore drill: secara rutin (misalnya sebulan sekali) restore backup ke server terpisah, lalu cek isinya:
SELECT (SELECT COUNT(*) FROM customers) AS customers,
(SELECT COUNT(*) FROM orders) AS orders;
Bandingkan dengan production. Waktu yang dibutuhkan drill itu juga RTO-mu yang sebenarnya. Simpan salinannya dengan aturan 3-2-1: 3 salinan data, di 2 media berbeda, 1 di luar lokasi (offsite). Pasang alert kalau job backup gagal atau ukuran filenya tiba-tiba mengecil.
⚠️ Jebakan yang sering ketemu
- Backup di server yang sama. Disk-nya mati, database dan backup-nya hilang bersamaan. Pakai 3-2-1.
- Gak pernah tes restore. Backup yang kosong, rusak, atau gak bisa dibuka baru ketahuan saat dibutuhkan.
- Rantai incremental putus. Satu file incremental hilang, semua yang sesudahnya gak bisa dipakai.
- Salah tulis jawaban di latihan. Kembalikan teks persis:
"pg_dump","pg_basebackup", dan"pg_basebackup + WAL archiving"dengan spasi di kiri dan kanan+.
TL;DR: Backup adalah salinan terpisah untuk restore setelah data hilang atau rusak. RPO adalah berapa banyak data terakhir yang boleh hilang, RTO adalah berapa lama aplikasi boleh mati. Full backup menyalin seluruh database; incremental cuma perubahan sejak backup terakhir apa pun (restore butuh semua file berurutan); differential semua perubahan sejak full terakhir (restore cukup full + differential terakhir). PITR memutar ulang WAL dari base backup sampai detik sebelum bencana. Di PostgreSQL: pg_dump untuk database kecil atau yang boleh lama down saat restore, pg_basebackup untuk database sedang yang gak boleh lama down, pg_basebackup + WAL archiving untuk database besar. Simpan 3-2-1, dan jalankan restore drill rutin: backup yang gak pernah dites bukan backup.