Restore di chapter sebelumnya mengembalikan kita ke satu momen tertentu: saat dump dibuat. Semua yang terjadi setelahnya — transaksi pelanggan, penyesuaian stok, pendaftaran baru — hilang bersama database, dan RPO kita terukur sepanjang jarak antara backup terakhir dan insiden. Point-in-time recovery (PITR) mempersempit luka itu menjadi nyaris nol: dengan berbekal satu backup dasar (base backup) plus rekaman setiap perubahan yang terjadi sesudahnya, kita bisa memutar ulang waktu sampai ke menit — bahkan detik — tepat sebelum musibah terjadi. Chapter ini membedah mekanismenya, menggambarkan arah waktunya, dan mensimulasikan (dengan jujur) satu insiden mini yang menelan data yang belum sempat tercadangkan.

Dua Komponen: Base Backup dan Binary Log #

PITR selalu tersusun dari dua bagian yang saling melengkapi. Bagian pertama adalah base backup — salinan penuh pada satu titik waktu, misalnya dump mysqldump mingguan. Bagian kedua adalah binary log — catatan berurutan atas setiap perubahan data yang diterapkan server sejak saat itu. Keduanya bekerja seperti buku harian: base backup adalah foto kondisi rumah pada hari Minggu, binary log adalah catatan semua perubahan yang terjadi hari demi hari. Memulihkan ke Rabu pukul 14:36 berarti membuka foto Minggu, lalu menerapkan catatan perubahan satu per satu sampai berhenti tepat sebelum waktu yang dituju.

Mekanisme ini menjelaskan mengapa binary log begitu penting bagi backup walau fungsinya yang lebih terkenal adalah replikasi: tanpa binary log, tidak ada catatan perubahan untuk diputar ulang, dan RPO kita terkunci pada jadwal backup terakhir. Sebaliknya, dengan binary log yang utuh sejak base backup terakhir, secara teori tidak ada satu baris pun perubahan yang hilang.

Simulasi Mini: Celah yang Ditinggalkan Restore Biasa #

Mari kita buktikan celah itu dengan tangan kita sendiri di server latihan. Siapkan belajar_backup dengan enam produk yang sudah akrab:

sql
DROP DATABASE IF EXISTS belajar_backup;
CREATE DATABASE belajar_backup;
USE belajar_backup;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE produk (
  id    INT AUTO_INCREMENT PRIMARY KEY,
  nama  VARCHAR(100) NOT NULL,
  harga INT NOT NULL,
  stok  INT NOT NULL DEFAULT 0
);

INSERT INTO produk (id, nama, harga, stok) VALUES
  (1, 'Kopi Toraja', 52000, 15),
  (2, 'Teh Melati', 28000, 40),
  (3, 'Gula Aren', 32000, 8);

INSERT INTO produk (nama, harga, stok) VALUES
  ('Susu Kental', 38000, 12),
  ('Kopi Robusta', 48000, 20),
  ('Teh Hijau', 30000, 25);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

Sekarang kita jalankan tiga babak dalam satu rangkaian dari terminal: ambil base backup, biarkan hari “berjalan” dengan tiga transaksi baru, lalu amati isi database:

bash
-- @test-bash
mysqldump -h 127.0.0.1 -P 3306 -u root --single-transaction belajar_backup > /tmp/pitr-base-belajar.sql
mysql -h 127.0.0.1 -P 3306 -u root -e "INSERT INTO belajar_backup.produk (nama, harga, stok) VALUES ('Kopi Luwak', 120000, 5), ('Teh Chamomile', 35000, 10), ('Gula Merah', 28000, 18);"
mysql -h 127.0.0.1 -P 3306 -u root -t -e "SELECT COUNT(*) AS jumlah_produk FROM belajar_backup.produk;"

Output yang Dihasilkan:

text
+---------------+
| jumlah_produk |
+---------------+
|             9 |
+---------------+

Sembilan baris — base backup mengabadikan enam, tiga sisanya hidup hanya di server. Lalu datanglah insiden: database terjatuh, dan kita pulihkan dari base backup satu-satunya yang ada:

bash
-- @test-bash
mysql -h 127.0.0.1 -P 3306 -u root -e "DROP DATABASE belajar_backup; CREATE DATABASE belajar_backup;"
mysql -h 127.0.0.1 -P 3306 -u root belajar_backup < /tmp/pitr-base-belajar.sql
mysql -h 127.0.0.1 -P 3306 -u root -N -e "SELECT COUNT(*) FROM belajar_backup.produk;"

Output yang Dihasilkan:

text
6

Enam. Restore berhasil sempurna — dan tiga transaksi setelah backup (Kopi Luwak, Teh Chamomile, Gula Merah) lenyap tanpa jejak karena tidak ada di file dump. Pada titik inilah PITR masuk: seandainya binary log aktif dan utuh, ketiga INSERT itu tercatat sebagai event, dan replay binlog akan mengembalikannya — sampai batas waktu yang kita pilih.

Membaca Arah Waktu #

Kunci PITR ada pada satu keputusan: replay harus berhenti sebelum event insiden. Diagram berikut memetakan alurnya:

Angka waktu dan posisi pada diagram adalah ilustrasi, tetapi polanya selalu sama. Replay yang berhenti terlalu cepat membiarkan sebagian transaksi hilang; replay yang melewati event insiden justru mengulang musibahnya — database dijatuhkan lagi tepat setelah selesai dipulihkan. Karena itu menentukan titik henti adalah langkah paling dikerjakan dengan hati-hati, dan sebaiknya dilatih di salinan server, bukan langsung di server yang sedang panik.

Langkah-Langkah PITR #

Dalam praktik, prosedur lengkapnya berbentuk lima langkah:

  1. Amankan bahan — salin base backup terakhir plus seluruh file binary log sejak backup itu ke lokasi aman; insiden jangan sampai ikut menelan bahan pemulihannya.
  2. Temukan titik insiden — telusuri binary log dengan mysqlbinlog (atau catat posisi yang dilaporkan saat insiden terjadi) untuk menentukan posisi atau waktu event pertama yang merusak. Perintah SHOW BINARY LOG STATUS (di MySQL versi lama: SHOW MASTER STATUS) menampilkan file binlog aktif beserta posisi ujungnya saat ini.
  3. Restore base backup — bangun ulang database dari dump ke server bersih, persis seperti chapter restore.
  4. Replay binlog sampai titik henti — ekstrak event dari binlog dan alirkan ke server, dengan batas --stop-position (posisi byte event, presisi) atau --stop-datetime (waktu, granular menit):
    bash
    -- @notest
    mysqlbinlog --stop-position=1420 /var/lib/mysql/binlog.000001 \
      | mysql -h 127.0.0.1 -P 3306 -u root
  5. Verifikasi dan ulangi bila perlu — periksa jumlah baris dan checksum; bila titik henti terbukti kurang pas, ulangi dari langkah 3 dengan titik henti yang disesuaikan. Iterasi seperti inilah alasan PITR latihan di server staging.

Perintah mysqlbinlog di langkah 4 sengaja tidak kita jalankan di server latihan. Binary log server kita memang tidak aktif — dan jujur, itulah realita yang perlu kita pahami dulu.

Realita Server Latihan dan Produksi #

Server latihan course ini dijalankan tanpa binary log (--skip-log-bin) demi menghemat disk dan menjaga latihan tetap ringan, sehingga replay PITR tidak bisa didemokan di sini — simulasi tiga baris yang hilang tadi adalah batas yang jujur dari lingkungan ini. Di server produksi berjalan normal, keadaannya terbalik: sejak MySQL 8.0, binary log aktif secara default, jadi komponen kedua PITR biasanya sudah tersedia tanpa pengaturan tambahan. Yang perlu dipastikan administrator adalah dua hal: binary log tidak dimatikan tanpa sadar (misalnya oleh konfigurasi warisan), dan retensinya cukup panjang untuk menampung seluruh rentang sejak base backup terakhir — binlog yang terhapus lebih cepat dari siklus backup memutus rantai replay.

RPO yang Mengecil #

Nilai akhir PITR diukur dari RPO. Jadwal backup mingguan saja memberi RPO terburuk hampir tujuh hari; tambahkan binary log yang diputar ulang sampai detik sebelum insiden, dan RPO menyusut ke hitungan menit atau detik — sebatas catatan terakhir yang sempat ditulis sebelum musibah. Biayanya pun jelas: ruang disk untuk binlog, disiplin menjaga rantainya, dan prosedur replay yang harus dilatih. Chapter berikutnya membedah jantung mekanisme ini dari sisi dalam: apa saja yang sebenarnya dicatat binary log, tiga format eventnya, cara membacanya dengan mysqlbinlog, dan — bagian yang paling sering tertukar — bedanya binary log dengan redo log InnoDB.

Referensi #