Kalimat pembuka section ini kini tiba saatnya dibuktikan: backup yang tidak pernah diuji restore-nya bukan backup. Sebuah file dump yang tergeletak rapi di disk hanyalah janji — kita berasumsi isinya lengkap, kredensialnya cocok, server tujuannya siap, dan ruang disknya cukup, padahal tidak satu pun asumsi itu terverifikasi sebelum restore benar-benar dijalankan. Chapter penutup ini membalik posisi kita: dari orang yang membuat backup menjadi orang yang harus memulihkannya di hari terburuk. Kita akan menjalankan drill pemulihan utuh di server latihan, menyusun checklist yang mengubah drill menjadi angka RTO nyata, lalu merapikan temuan dan runbook agar prosedur yang sudah terbukti bisa dijalankan siapa pun — bahkan oleh orang yang panik.

Janji yang Belum Diperiksa #

Banyak hal bisa salah diam-diam di antara “backup berhasil dibuat” dan “database berhasil dipulihkan”. File arsip bisa korup di tengah penyalinan; user yang dipakai skrip backup bisa kehilangan hak aksesnya setelah rotasi password; server tujuan bisa menjalankan versi MySQL yang lebih tua dan menolak collation dari dump; stored procedure bisa tertinggal karena opsi --routines terlewat; disk tujuan bisa kehabisan ruang justru saat ekstraksi berlangsung. Tidak ada satu pun dari kegagalan itu yang terlihat dari ukuran file dump yang “tampak normal”.

Karena itu ujian sesungguhnya dari seluruh strategi backup kita bukan membaca log sukses, melainkan restore yang selesai dengan data yang cocok. Drill inilah yang mengubah RTO dari angka asumsi menjadi angka terukur — berapa menit persisnya dari “database mati” sampai “aplikasi melayani lagi”. Dan seperti jadwal backup itu sendiri, drill pun harus terjadwal: sekali sebulan atau sekali per kuartal adalah ritme yang umum, karena prosedur, server, dan kredensial selalu bergeser pelan-pelan di balik punggung kita.

Drill Pemulihan: Satu Siklus Hidup Lengkap #

Drill kita memakai siklus hidup penuh sebuah database uji: lahir, dicadangkan, dijatuhkan, dipulihkan, diverifikasi, lalu dibersihkan. Database uji sengaja diberi nama belajar_uji agar mentalitasnya jelas — ini pasien latihan, bukan data produksi. Seluruh proses berjalan dari terminal, persis seperti operator yang menangani insiden sungguhan.

Tahap pertama membangun korban beserta catatan pembandingnya — dan mencadangkannya ke /tmp/uji-backup.sql:

bash
-- @test-bash
mysql -h 127.0.0.1 -P 3306 -u root -e "DROP DATABASE IF EXISTS belajar_uji; CREATE DATABASE belajar_uji; CREATE TABLE belajar_uji.produk (id INT AUTO_INCREMENT PRIMARY KEY, nama VARCHAR(100) NOT NULL, harga INT NOT NULL, stok INT NOT NULL DEFAULT 0); INSERT INTO belajar_uji.produk (id, nama, harga, stok) VALUES (1,'Kopi Toraja',52000,15),(2,'Teh Melati',28000,40),(3,'Gula Aren',32000,8),(4,'Susu Kental',38000,12),(5,'Kopi Robusta',48000,20),(6,'Teh Hijau',30000,25);"
mysqldump -h 127.0.0.1 -P 3306 -u root --single-transaction belajar_uji > /tmp/uji-backup.sql
mysql -h 127.0.0.1 -P 3306 -u root -t -e "SELECT COUNT(*) AS jumlah_produk FROM belajar_uji.produk; CHECKSUM TABLE belajar_uji.produk;"

Output yang Dihasilkan:

text
+---------------+
| jumlah_produk |
+---------------+
|             6 |
+---------------+
+--------------------+----------+
| Table              | Checksum |
+--------------------+----------+
| belajar_uji.produk |  1017492 |
+--------------------+----------+

Dua angka terakhir adalah standar emas drill ini: jumlah_produk sebesar 6 dan checksum 1017492. Kita memakai pasangan yang sama dengan chapter restore-database — COUNT(*) untuk jumlah baris, CHECKSUM TABLE untuk sidik jari isi — dan checksum memang dihitung dari isi baris demi baris, sehingga tabel dengan definisi serta data identik menghasilkan angka yang sama seperti produk milik belajar_backup pada chapter itu.

Tahap kedua adalah musibah, pemulihan, dan pembersihan dalam satu rangkaian: jatuhkan database, buktikan ia lenyap, ciptakan wadah kosong, pulihkan dari file, lalu ukur hasilnya terhadap standar emas:

bash
-- @test-bash
mysql -h 127.0.0.1 -P 3306 -u root -e "DROP DATABASE belajar_uji;"
mysql -h 127.0.0.1 -P 3306 -u root -N -e "SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name = 'belajar_uji';"
mysql -h 127.0.0.1 -P 3306 -u root -e "CREATE DATABASE belajar_uji;"
mysql -h 127.0.0.1 -P 3306 -u root belajar_uji < /tmp/uji-backup.sql
mysql -h 127.0.0.1 -P 3306 -u root -t -e "SELECT COUNT(*) AS jumlah_produk FROM belajar_uji.produk; CHECKSUM TABLE belajar_uji.produk;"
mysql -h 127.0.0.1 -P 3306 -u root -e "DROP DATABASE belajar_uji;"

Output yang Dihasilkan:

text
0
+---------------+
| jumlah_produk |
+---------------+
|             6 |
+---------------+
+--------------------+----------+
| Table              | Checksum |
+--------------------+----------+
| belajar_uji.produk |  1017492 |
+--------------------+----------+

Angka 0 di baris pertama membuktikan belajar_uji benar-benar terhapus dari katalog server — drill ini tidak bercanda. Setelah restore, COUNT(*) kembali 6 dan checksum kembali 1017492: jumlah sama, isi sama. Baris CREATE DATABASE sebelum restore sengaja kita tulis sendiri karena dump dibuat tanpa --databases — pelajaran error 1049 dari chapter restore-database tetap berlaku di sini. Statement DROP DATABASE di baris terakhir adalah kebersihan meja latihan; di drill sungguhan, database yang berhasil dipulihkan justru dibiarkan hidup dan diperiksa lebih lanjut.

Dalam drill produksi, setiap fase rangkaian ini dicatat waktunya: jam saat insiden disimulasikan, jam saat restore selesai, jam saat verifikasi lolos. Selisihnya adalah RTO aktual Anda — angka yang tidak bisa dibeli dengan peralatan mahal, hanya dengan latihan.

Drill Berkala ke Server Staging #

Menguji restore di server produksi itu seperti mencoba rompi penyelamat sambil berenang di laut bermusim badai — sebagian besar tim lebih memilih kolam latihan. Server staging adalah kolam itu: mesin terpisah berisi salinan atau replika ringan data produksi, tempat operator bisa menjatuhkan dan membangkitkan database tanpa risiko mengganggu pelanggan. Drill ke staging menguji rantai penuh secara jujur: file backup disalin dari tempat penyimpanannya, kredensial diuji, lalu restore dijalankan di mesin yang konfigurasinya menyerupai produksi namun tidak melayani siapa pun.

Server latihan course ini punya satu keterbatasan yang sudah kita kenal di chapter binary log: binary log tidak aktif, sehingga latihan replay PITR tidak bisa didemokan di sini. Drill di staging sungguhan sebaiknya mencakup satu babak tambahan: putar ulang binlog setelah restore base backup sampai titik waktu tertentu, persis alur chapter point-in-time recovery. Babak inilah yang memverifikasi rantai RPO — seberapa dekat data yang kembali ke momen terakhir sebelum insiden.

Checklist Drill #

Drill yang baik tidak berhenti pada “restore berhasil”. Checklist berikut mengubah satu sesi latihan menjadi angka dan bukti yang bisa dilaporkan:

Item periksaCara memeriksaLolos bila
Waktu restore tercatatCatat jam tiap fase: ambil arsip, restore, verifikasiRTO aktual ≤ target yang ditetapkan
COUNT dan CHECKSUM cocokBandingkan angka pra-dan pasca-restoreKedua angka identik dengan catatan pra-insiden
Aplikasi menyalaHubungkan aplikasi ke hasil restore, jalankan fungsi intiLogin dan transaksi uji berjalan normal
Spot-check dataPeriksa beberapa baris penting secara manualBaris terakhir sebelum insiden hadir dan benar
Runbook dipakaiOperator lain mengikuti runbook tanpa dibantuProsedur selesai tanpa improvisasi

Baris terakhir adalah yang paling sering dilupakan: drill yang hanya bisa diselesaikan oleh penulisnya sendiri belum membuktikan prosedur — ia baru membuktikan ingatan satu orang. Serahkan runbook kepada rekan yang tidak menulisnya, lalu catat di titik mana saja ia tersandung; titik-titik itulah bagian runbook yang perlu diperbaiki.

Temuan Umum Drill #

Drill yang gagal bukan kegagalan drill — ia justru deliverable paling berharga, karena menemukan masalah di hari latihan alih-alih hari insiden. Lima temuan ini muncul berulang di berbagai tim:

  • Dump usang — backup terakhir sukses ternyata berumur berminggu-minggu; jadwal mogok diam-diam dan tidak ada yang memeriksa umur arsip. Perbaikannya adalah pemantauan umur file seperti chapter backup scheduling.
  • Kredensial salah — user yang dipakai restore sudah tidak ada, password berganti, atau hak aksesnya dicabut saat rotasi keamanan. Simpan kredensial pemulihan di tempat yang ikut teruji oleh drill.
  • Versi target berbeda — dump dari MySQL 8 ditolak server lama dengan pesan collation tak dikenal. Arah aman restore selalu dari versi lama ke baru, atau sesama versi sama.
  • Routines dan DEFINER hilang — dump dibuat tanpa --routines, atau procedure ikut serta tetapi klausa DEFINER menunjuk user yang tidak ada di server tujuan. Keduanya sudah kita bedah di chapter mysqldump dan restore.
  • Penyimpanan penuh — restore berhenti di tengah jalan karena arsip terkompresi 2 GB mengembang menjadi 20 GB SQL yang harus diproses. Ruang disk yang cukup adalah prasyarat, bukan afterthought.

Isi Runbook Pemulihan #

Semua pengetahuan di atas kehilangan nilainya bila hanya hidup di kepala satu orang. Runbook adalah dokumen prosedur pemulihan yang ditulis selangkah demi selangkah — cukup detail untuk diikuti orang yang panik, cukup ringkas untuk tidak ditunda bacaannya. Kerangka isinya kurang lebih begini:

text
RUNBOOK PEMULIHAN DATABASE TOKO
Terakhir diuji: drill bulanan oleh operator jaga

1. PRASYARAT
   - Akses ke server cadangan dan login-path "backup" (kredensial tersimpan aman)
   - Ruang disk minimal 3x ukuran arsip terbesar
   - Versi MySQL target sama dengan atau lebih baru dari server sumber

2. LANGKAH PEMULIHAN
   a. Ambil arsip termuda dari /var/backup/mysql/
   b. Pulihkan: zcat arsip | mysql
   c. Replay binary log bila perlu sampai titik henti yang ditetapkan
   d. Verifikasi: COUNT, CHECKSUM, spot-check transaksi terakhir
   e. Hidupkan aplikasi dan jalankan transaksi uji

3. KONTAK DAN ESKALASI
   - Budi (DBA) - telepon di daftar on-call
   - Kepala operasional - keputusan bisnis bila data hilang tak terhindarkan
   - Penyedia penyimpanan offsite - bila salinan tidak terjangkau

4. BATAS KEPUTUSAN
   - Target RTO 1 jam; eskalasi ke kepala operasional bila 45 menit terlampaui

Empat bagian itu adalah minimal: langkah bernomor, prasyarat, kontak dan eskalasi, serta batas keputusan. Dua hal menentukan runbook hidup atau mati. Pertama, tempat penyimpanannya: runbook yang hanya ada di server yang bisa mati ikut lenyap bersama insiden — simpan salinan cetak dan salinan di penyimpanan terpisah yang dapat diakses dari ponsel. Kedua, tanggal uji terakhir: runbook yang belum diuji enam bulan adalah tebakan yang diketik rapi, jadi setiap drill harus menulis ulang baris “terakhir diuji”.

RTO dan RPO Diverifikasi terhadap Target #

Bab penutup section ini mengembalikan kita ke dua angka pembuka section: RPO dan RTO. Setelah drill, keduanya berhenti menjadi harapan dan mulai menjadi hasil ukur. RTO aktual terbaca dari catatan waktu drill — dan bilamana angka itu melebihi target, keputusannya konkret: perpendek rantai restore (arsip terkompresi yang lebih kecil, restore paralel), atau pindah ke keluarga physical backup yang memulihkan dengan menyalin file, atau naik kelas ke arsitektur yang tidak menunggu restore sama sekali. RPO diverifikasi dari rantai data yang kembali: backup terakhir yang berhasil plus binlog yang berhasil diputar ulang menunjukkan titik waktu tertentu — jarak titik itu ke momen insiden adalah kehilangan maksimum yang harus disetujui bisnis.

Kalau target RTO Anda mengecil di bawah kemampuan restore mana pun, saatnya keluar dari dunia backup dan masuk ke dunia high availability: server replika yang terus mengikuti sumbernya dan siap mengambil alih dalam hitungan menit. Itulah section berikutnya — replikasi dan ketersediaan tinggi — penutup perjalanan course ini.

Referensi #