Database toko online menyimpan seluruh riwayat bisnis: pelanggan, pesanan, dan pembayaran. Perangkat keras bisa rusak, orang bisa menjalankan DELETE tanpa WHERE, dan aplikasi bisa punya bug yang menulis data salah. Backup adalah salinan data yang disimpan terpisah untuk momen-momen buruk tersebut — tetapi yang menentukan keselamatan bisnis bukan proses backup semata, melainkan pemulihan (recovery) yang terbukti berhasil. Bab ini memetakan strategi backup, menampilkan perintah resmi PostgreSQL, dan menguji backup online SQLite secara nyata dengan Python.
Empat Strategi Backup #
Dua sumbu memisahkan jenis backup: cakupan (penuh atau bertahap) dan bentuk hasilnya (skrip logis atau berkas fisik). Keduanya saling lepas sehingga menghasilkan empat kombinasi.
| Strategi | Isi | Kelebihan | Kekurangan |
|---|---|---|---|
| Full backup | seluruh database, setiap kali | restore paling sederhana | lambat dan boros ruang bila data besar |
| Incremental backup | perubahan sejak backup terakhir | cepat dan hemat ruang | restore berantai: butuh basis full + seluruh increment |
| Logical backup | skrip SQL atau data dalam format baca (mis. pg_dump) | portabel antar versi dan platform, bisa dipilih per tabel | restore lambat untuk data besar |
| Physical backup | berkas data mentah (blok, WAL) | restore cepat, dasar replikasi dan PITR | terikat versi dan arsitektur yang sama |
Praktik umum menggabungkannya: full backup mingguan sebagai fondasi, incremental harian untuk efisiensi, dan physical backup berkelanjutan bila target pemulihan menuntut kecepatan.
Backup di PostgreSQL: pg_dump dan pg_basebackup #
PostgreSQL menyediakan dua jalur resmi. Jalur logis memakai pg_dump, yang membaca definisi skema dan isi tabel lalu menuliskannya ke satu berkas terkompresi (format -Fc); pemulihannya dilakukan oleh pg_restore. Jalur fisik memakai pg_basebackup, yang menyalin berkas data mentah beserta arus WAL (write-ahead log) sehingga hasilnya adalah replika utuh yang siap dihidupkan. Perintah berikut adalah bentuk pemakaiannya — tidak dieksekusi di lingkungan bab ini karena tidak ada server PostgreSQL berjalan.
# Backup logis: seluruh database toko_online dalam format custom terkompresi
pg_dump -h localhost -U budi -Fc toko_online -f toko_online_hari_ini.dump
# Pemulihan logis ke database tujuan yang sudah dibuat
pg_restore -h localhost -U budi -d toko_online_baru toko_online_hari_ini.dump
# Backup fisik: salinan berkas data + WAL distreaming sambil berjalan
pg_basebackup -h localhost -U pengguna_backup \
-D /var/lib/postgresql/backup_dasar \
-X stream -PFlag -X stream memerintahkan pg_basebackup mengirim arus WAL secara langsung selama penyalinan, sehingga hasil backup konsisten hingga detik terakhinya selesai; -P menampilkan kemajuan proses. Rujukan lengkap keduanya ada di Backup and Restore PostgreSQL
dan halaman pg_dump
.
Backup Online di SQLite #
SQLite menyiapkan mekanisme cadangan yang aman lewat API backup: penyalinan berjalan per halaman dengan tetap menghormati kunci, sehingga sumber tidak perlu dihentikan. Modul sqlite3 Python membungkus API tersebut dalam bentuk Connection.backup(target). Skrip berikut menguji tiga hal sekaligus: proses backup, integritas hasil salinan, dan sifat point-in-time — cadangan mempertahankan keadaan saat disalin meski sumber terus berubah.
import sqlite3
from pathlib import Path
SUMBER = Path("toko.db")
CADANGAN = Path("cadangan.db")
if SUMBER.exists():
SUMBER.unlink()
if CADANGAN.exists():
CADANGAN.unlink()
sumber = sqlite3.connect(SUMBER)
sumber.executescript("""
CREATE TABLE pelanggan (id INTEGER PRIMARY KEY, nama TEXT, kota TEXT);
CREATE TABLE pesanan (id INTEGER PRIMARY KEY, pelanggan_id INTEGER, total INTEGER);
INSERT INTO pelanggan VALUES (1, 'Budi Santoso', 'Jakarta');
INSERT INTO pelanggan VALUES (2, 'Siti Aminah', 'Bandung');
INSERT INTO pesanan VALUES (101, 1, 250000);
INSERT INTO pesanan VALUES (102, 2, 480000);
""")
# backup online: sumber tetap terbuka dan bisa dipakai proses lain
cadangan = sqlite3.connect(CADANGAN)
sumber.backup(cadangan)
cadangan.close()
print("backup selesai")
def ringkas(koneksi, label):
jumlah = koneksi.execute("SELECT COUNT(*) FROM pelanggan").fetchone()[0]
total = koneksi.execute("SELECT SUM(total) FROM pesanan").fetchone()[0]
sehat = koneksi.execute("PRAGMA integrity_check").fetchone()[0]
print(f"{label}: {jumlah} pelanggan, total pesanan {total}, "
f"integritas {sehat}")
ringkas(sumber, "sumber saat backup")
# toko terus berjualan setelah backup
sumber.execute("INSERT INTO pesanan VALUES (103, 1, 150000)")
sumber.commit()
cek_cadangan = sqlite3.connect(CADANGAN)
ringkas(sumber, "sumber setelah pesanan baru")
ringkas(cek_cadangan, "cadangan (titik waktu backup)")
sumber.close()
cek_cadangan.close()Output yang Dihasilkan:
backup selesai
sumber saat backup: 2 pelanggan, total pesanan 730000, integritas ok
sumber setelah pesanan baru: 2 pelanggan, total pesanan 880000, integritas ok
cadangan (titik waktu backup): 2 pelanggan, total pesanan 730000, integritas okMari kita telaah baris-baris kode di atas:
- Baris 7-20 (persiapan): berkas lama dibuang supaya setiap eksekusi mulai bersih, lalu
executescriptmembuat dua tabel berisi data toko.executescriptmenuntaskan transaksinya sendiri, sehingga sumber berstatus bersih saat disalin. - Baris 22-26 (proses backup): koneksi
cadangandibuka ke berkas tujuan yang masih kosong, lalusumber.backup(cadangan)menyalin seluruh halaman database. Metode ini menerima parameterpages(besar potongan per langkah) dansleep(jeda saat sumber sedang dikunci penulis lain) — keduanya memakai nilai wajar secara bawaan. - Baris 29-34 (
ringkas): fungsi pemeriksa membaca jumlah pelanggan, total pesanan, dan hasilPRAGMA integrity_check(nilaiokberarti struktur berkas sehat). - Baris 39-45 (bukti point-in-time): setelah backup, satu pesanan baru disisipkan ke sumber. Perbandingan akhir menunjukkan sumber bertambah menjadi 880000, sedangkan cadangan tetap 730000 — persis keadaan saat disalin.
RPO dan RTO: Mengukur Target Pemulihan #
Dua akronim mengubah diskusi backup dari selera menjadi angka. RPO (Recovery Point Objective) adalah batas usia data yang boleh hilang — “backup tengah malam” berarti RPO 24 jam, sehingga pesanan yang masuk pukul 23.59 ikut hilang bila server rusak pukul 00.01. RTO (Recovery Time Objective) adalah batas lama layanan boleh mati sebelum pemulihan selesai. Kedua angka menentukan strategi: toko online yang tidak boleh berhenti menerima pesanan menuntut RPO dan RTO kecil (physical backup berkelanjutan, failover otomatis), sedangkan data analitik yang dimuat ulang dari sumber lain bisa menerima RPO satu hari penuh dengan pg_dump harian.
| Kebutuhan bisnis | RPO | RTO | Strategi yang cocok |
|---|---|---|---|
| Transaksi pembayaran | detik - menit | menit | physical backup + WAL, replikasi |
| Data operasional toko | menit - jam | jam | pg_dump berkala + incremental |
| Data warehouse analitik | hingga 24 jam | jam - hari | full backup harian cukup |
Aturan 3-2-1 #
Berapa banyak salinan yang cukup? Praktik yang sudah lama diuji industri merumuskannya sebagai aturan 3-2-1: 3 salinan data (satu utama, dua cadangan), tersimpan di 2 jenis media berbeda (misalnya server database dan penyimpanan objek), dengan 1 salinan berada di lokasi terpisah secara geografis — sehingga bencana di satu lokasi tidak menghapus semua salinan sekaligus. Aturan ini juga menuntut satu kebiasaan yang sering dilewatkan: uji restore secara berkala. Cadangan yang belum pernah dipulihkan adalah tebakan, bukan jaminan.
Backup melindungi data dari bencana, tetapi backup bukan alat ketersediaan layanan — pemulihan dari backup memakan waktu. Bila kebutuhannya adalah tetap melayani pembaca saat database utama sibuk atau terganggu, jawabannya adalah replikasi, topik Chapter Replikasi Database.