Saat Migrasi Data Gagal: Strategi Rollback yang Benar-Benar Berhasil

Anda baru saja men-deploy migrasi database ke produksi. Skrip berjalan selama dua belas menit, mengubah tiga tabel, memindahkan data antar kolom, lalu gagal pada pernyataan terakhir. Setengah perubahan sudah teraplikasi. Setengahnya lagi tidak. Aplikasi Anda sekarang melayani error karena skema yang diharapkan belum sepenuhnya ada.

Inilah momen ketika sebagian besar tim menyadari bahwa melakukan rollback migrasi data tidak sama dengan rollback deployment aplikasi. Dengan kode aplikasi, Anda cukup mengganti binary atau image container, dan versi lama berjalan kembali. Dengan data, Anda tidak bisa membatalkan penghapusan kolom hanya dengan men-deploy ulang kode lama. Kolomnya sudah hilang. Data yang ada di dalamnya mungkin juga sudah hilang.

Strategi rollback untuk migrasi data harus sudah ada sebelum migrasi dimulai. Merencanakannya setelah kegagalan terjadi sudah terlambat.

Backup Sebelum Migrasi, Bukan Setelahnya

Mekanisme rollback paling andal adalah snapshot lengkap database yang diambil tepat sebelum migrasi dimulai. Ini bukan backup harian Anda. Ini adalah salinan point-in-time yang menangkap status data persis sebelum perubahan.

Backup ini harus diotomatisasi sebagai bagian dari pipeline. Sebelum langkah migrasi dijalankan, pipeline memicu database dump, snapshot, atau penghentian replikasi yang membuat titik pemulihan. Jika langkah backup gagal, pipeline berhenti. Migrasi tidak dijalankan. Ini menghilangkan kesalahan manusia karena lupa mengambil backup manual sebelum menekan deploy.

Diagram alir berikut mengilustrasikan jalur keputusan setelah migrasi gagal, membantu Anda memilih metode rollback yang sesuai berdasarkan situasi.

flowchart TD A[Backup Pra-Migrasi Dibuat] --> B[Migrasi Berjalan] B --> C{Migrasi Berhasil?} C -->|Ya| D[Selesai] C -->|Tidak| E{Pilih Metode Rollback} E -->|Perubahan destruktif atau kehilangan data| F[Point-in-Time Recovery] E -->|Perubahan skema reversibel| G[Rollback Versi - Down Migration] E -->|Snapshot lengkap tersedia| H[Restore Snapshot Pra-Migrasi] F --> I[Investigasi Akar Masalah] G --> I H --> I I --> J[Perbaiki Skrip Migrasi] J --> B

Untuk database cloud, ini biasanya berarti mengambil snapshot volume atau membuat klon instance. Untuk database self-hosted, berarti menjalankan perintah dump atau menggunakan snapshot filesystem. Yang penting adalah backup tersebut dapat diverifikasi. File backup yang tidak bisa direstore bukanlah backup.

Rollback Versi Migrasi Punya Keterbatasan

Sebagian besar framework migrasi mendukung versi maju dan mundur. Flyway menyebutnya migrate dan undo. Liquibase menyebutnya update dan rollback. Alembic menyebutnya upgrade dan downgrade. Alat-alat ini dapat membalikkan perubahan skema dengan menjalankan skrip down migration.

Masalahnya, down migration hanya bekerja aman untuk perubahan yang reversibel. Menambahkan kolom nullable bersifat reversibel: down migration menghapus kolom tersebut, dan tidak ada data yang hilang. Mengganti nama kolom bersifat reversibel jika down migration mengembalikan namanya. Tapi perubahan destruktif adalah cerita lain. Jika Anda menghapus kolom, down migration bisa membuatnya kembali, tetapi data yang ada di kolom itu sudah hilang. Jika Anda mentransformasi data dari satu format ke format lain, down migration bisa membalikkan transformasi hanya jika Anda menyimpan nilai asli di suatu tempat.

Rollback versi berguna untuk menangkap kesalahan lebih awal, seperti migrasi yang di-deploy ke lingkungan yang salah atau perubahan skema yang merusak query. Tapi ini bukan jaring pengaman untuk kehilangan data. Mengandalkan down migration saja adalah kesalahan umum yang menyebabkan kehilangan data saat rollback.

Point-in-Time Recovery sebagai Jaring Pengaman

Strategi rollback paling kokoh tidak bergantung pada skrip migrasi sama sekali. Point-in-time recovery menggunakan log transaksi database untuk mengembalikan database ke momen sebelum migrasi dimulai.

Begini cara kerjanya. Database terus-menerus menulis log transaksi atau write-ahead log yang mencatat setiap perubahan. Jika Anda memiliki log ini dan backup dasar, Anda dapat memutar ulang log hingga timestamp tertentu. Ketika migrasi gagal pada pukul 14:00, Anda mengembalikan database ke pukul 13:59, sebelum migrasi dimulai. Semua perubahan yang dibuat oleh migrasi hilang, dan database kembali ke status aslinya terlepas dari seberapa destruktif migrasi tersebut.

Point-in-time recovery memerlukan persiapan. Database harus dikonfigurasi untuk mengarsipkan log transaksi secara terus-menerus. Tim harus memiliki alat dan izin untuk melakukan restore ke waktu tertentu. Dan prosesnya harus diuji secara teratur. Banyak tim baru menyadari bahwa setup point-in-time recovery mereka rusak saat dibutuhkan selama insiden.

Pendekatan ini berfungsi untuk migrasi apa pun, termasuk yang destruktif. Tidak peduli apakah migrasi menambahkan kolom, menghapus tabel, atau mentransformasi jutaan baris. Ini hanya memundurkan waktu.

Uji Rollback, Bukan Hanya Migrasinya

Migrasi yang lulus semua pengujian di staging tetap bisa gagal di produksi karena volume data yang tidak terduga, konflik locking, atau kasus tepi dalam data. Hal yang sama berlaku untuk rollback. Satu-satunya cara untuk tahu bahwa rollback berhasil adalah dengan mengujinya.

Di lingkungan staging Anda, jalankan migrasi. Kemudian coba rollback menggunakan masing-masing strategi Anda: down migration, backup pra-migrasi, dan point-in-time recovery. Ukur berapa lama setiap metode memakan waktu. Jika point-in-time recovery memakan waktu empat jam, itu adalah informasi penting untuk diketahui sebelum insiden produksi.

Jika rollback gagal atau terlalu lama, perbaiki prosesnya sebelum Anda membutuhkannya. Pengujian ini harus menjadi bagian dari pipeline Anda. Sebuah job terjadwal dapat menjalankan siklus migrasi dan rollback di staging setiap minggu untuk memverifikasi bahwa mekanisme pemulihan masih berfungsi setelah perubahan infrastruktur.

Setelah Rollback, Investigasi Sebelum Mencoba Lagi

Ketika rollback berhasil, reaksi alami adalah memperbaiki skrip migrasi dan menjalankannya lagi. Tahan impuls itu. Kegagalan mungkin mengungkapkan masalah yang lebih dalam: inkonsistensi data yang tidak diperhitungkan oleh migrasi, race condition dengan proses lain, atau kesalahpahaman tentang skema.

Investigasi akar masalah terlebih dahulu. Periksa log migrasi. Lihat data yang menyebabkan kegagalan. Tinjau apakah migrasi mengasumsikan bentuk data yang tidak ada di produksi. Hanya setelah Anda memahami mengapa gagal, Anda boleh memodifikasi skrip dan mencoba lagi.

Daftar Periksa Praktis untuk Rollback Migrasi

  • Otomatiskan langkah backup pra-migrasi di pipeline. Jika backup gagal, pipeline gagal.
  • Tulis down migration hanya untuk perubahan skema yang reversibel. Jangan mengandalkannya untuk operasi destruktif.
  • Konfigurasikan point-in-time recovery untuk database Anda dan uji setidaknya sekali per kuartal.
  • Uji rollback di staging sebelum setiap migrasi produksi, bukan hanya saat setup awal.
  • Dokumentasikan prosedur rollback dan perkiraan waktu restore untuk setiap lingkungan.
  • Setelah rollback, investigasi akar masalah sebelum mencoba migrasi lagi.

Kesimpulan Konkret

Rollback migrasi data bukanlah skrip yang Anda jalankan. Ini adalah sistem yang Anda bangun sebelum migrasi dimulai. Backup pra-migrasi adalah garis pertahanan pertama Anda. Point-in-time recovery adalah jalan terakhir Anda. Down migration hanya berguna untuk kasus sempit di mana perubahan bersifat reversibel. Uji semuanya di staging, dokumentasikan prosedurnya, dan jangan pernah berasumsi bahwa rollback akan berhasil sampai Anda telah membuktikannya.