Ketika Migrasi Database Membutuhkan Perpisahan yang Bersih: Fase Cutover
Bayangkan skenario ini: tim Anda telah menghabiskan waktu berminggu-minggu untuk memigrasikan data dari skema database lama ke yang baru. Pola expand-contract telah berjalan mulus. Aplikasi Anda telah menulis ke struktur lama dan baru. Skrip backfill telah memindahkan data historis. Pemeriksaan verifikasi telah lolos. Semuanya terlihat baik di atas kertas.
Namun kini tibalah momen yang membuat banyak engineer gugup: mengalihkan aplikasi Anda untuk membaca secara eksklusif dari struktur baru. Inilah fase cutover, dan di sinilah banyak migrasi database berhasil dengan bersih atau justru menciptakan insiden produksi yang tidak terduga.
Apa Arti Sebenarnya Cutover
Cutover adalah titik di mana aplikasi Anda berhenti membaca dari struktur lama dan sepenuhnya bergantung pada struktur baru. Kedengarannya sederhana, tetapi dalam praktiknya membutuhkan koordinasi dan verifikasi yang cermat.
Sebelum cutover, aplikasi Anda berada dalam keadaan dual-read. Data baru telah ditulis ke kedua struktur sejak migrasi dimulai. Data historis telah di-backfill. Aplikasi membaca dari dua tempat: struktur lama untuk data yang sudah ada sebelum migrasi, dan struktur baru untuk data yang ditulis setelahnya.
Cutover menghapus logika dual-read tersebut. Kode aplikasi Anda berubah sehingga setiap permintaan baca hanya mengarah ke struktur baru. Ini biasanya adalah perubahan kode dan deployment, bukan perubahan skema. Anda memperbarui jalur baca, membangun aplikasi, dan men-deploy-nya seperti pembaruan fitur lainnya.
Diagram urutan berikut mengilustrasikan transisi dari dual-read ke cutover:
Berikut adalah contoh sederhana dari perubahan kode tersebut di layanan Node.js:
// Before cutover: dual-read logic
async function getUserProfile(userId) {
// Try new structure first for recent data
const newProfile = await db.query(
'SELECT * FROM user_profiles_v2 WHERE user_id = $1', [userId]
);
if (newProfile.rows.length > 0) {
return newProfile.rows[0];
}
// Fall back to old structure for legacy data
const oldProfile = await db.query(
'SELECT * FROM user_profiles WHERE user_id = $1', [userId]
);
return oldProfile.rows[0] || null;
}
// After cutover: single-read logic
async function getUserProfile(userId) {
const profile = await db.query(
'SELECT * FROM user_profiles_v2 WHERE user_id = $1', [userId]
);
return profile.rows[0] || null;
}
Risiko yang Tidak Bisa Anda Abaikan
Bahaya selama cutover adalah kegagalan parsial. Jika beberapa instance aplikasi masih membaca dari struktur lama sementara yang lain sudah beralih, Anda bisa mendapatkan hasil yang tidak konsisten. Seorang pengguna mungkin melihat data yang berbeda tergantung server mana yang menangani permintaan mereka.
Inilah mengapa strategi cutover itu penting. Ada dua pendekatan utama:
Big bang cutover mengalihkan semua instance sekaligus. Cepat dan sederhana untuk dikoordinasikan, tetapi jika ada yang salah, semua pengguna akan terpengaruh seketika.
Gradual cutover mengalihkan instance secara bertahap, seringkali berdasarkan region, availability zone, atau grup pengguna. Ini membatasi radius dampak. Jika Anda cutover satu availability zone dan melihat error, Anda bisa menyelidiki sebelum melanjutkan ke zone berikutnya. Konsekuensinya adalah kompleksitas yang lebih tinggi dalam koordinasi dan monitoring.
Sebagian besar tim dengan pengalaman produksi lebih memilih gradual cutover untuk migrasi database. Upaya koordinasi ekstra sepadan dengan jaring pengaman yang didapatkan.
Menemukan Dependensi Tersembunyi
Setelah cutover, aplikasi Anda tidak lagi membaca dari struktur lama. Tapi apakah benar hanya aplikasi Anda satu-satunya yang melakukannya? Di lingkungan produksi, banyak service, batch job, skrip pelaporan, dan query manual sering berbagi database yang sama.
Kesalahan umum adalah menganggap bahwa memperbarui aplikasi utama saja sudah cukup. Sementara itu, batch job malam yang berjalan jam 2 pagi masih melakukan query ke kolom lama. Atau seorang analis data menjalankan laporan manual setiap Senin menggunakan tabel lama. Dependensi tersembunyi ini akan menyebabkan kegagalan atau menghasilkan data basi setelah cutover.
Cara paling andal untuk menemukannya adalah dengan monitoring query database. Aktifkan alat seperti pg_stat_statements di PostgreSQL atau performance_schema di MySQL. Cari query apa pun yang mereferensikan kolom atau tabel lama. Jalankan monitoring ini setidaknya selama satu siklus penuh dari semua proses yang diketahui. Jika Anda memiliki pekerjaan pelaporan mingguan, tunggu satu minggu penuh setelah cutover sebelum menyatakan struktur lama tidak digunakan.
Beberapa tim juga menjalankan staging test di mana mereka mencabut akses baca ke kolom lama dan menjalankan semua skenario aplikasi yang diketahui. Jika tidak ada error yang muncul, kemungkinan besar produksi aman untuk langkah selanjutnya.
Apa yang Terjadi Setelah Cutover
Setelah cutover selesai dan semua dependensi dikonfirmasi bersih, aplikasi Anda sepenuhnya berada di format baru. Struktur lama masih ada di database, tetapi tidak ada yang membacanya. Inilah titik di mana Anda bisa mulai merencanakan fase contract: menghapus struktur lama sepenuhnya.
Namun jangan terburu-buru menghapus. Bahkan setelah cutover, pertahankan struktur lama untuk periode keamanan. Lamanya tergantung pada keyakinan tim Anda dan biaya untuk menyimpan kolom atau tabel tambahan. Beberapa tim menyimpannya selama seminggu. Yang lain menyimpannya selama sebulan, terutama jika migrasi melibatkan data pelanggan yang kritis.
Selama periode ini, pantau setiap alert atau log error yang mungkin mengindikasikan dependensi yang belum ditemukan. Jika tidak ada yang muncul, Anda bisa melanjutkan dengan percaya diri untuk menghapus struktur lama.
Daftar Periksa Praktis untuk Cutover
Sebelum Anda mengeksekusi cutover di produksi, jalankan daftar periksa ini:
- Semua data historis telah di-backfill dan diverifikasi
- Dual-write telah berjalan tanpa error setidaknya selama satu siklus bisnis penuh
- Perubahan kode jalur baca sudah siap dan telah di-review
- Rencana rollback sudah didokumentasikan: cara mengembalikan pembacaan ke struktur lama jika diperlukan
- Monitoring query database sudah diaktifkan dan dikonfigurasi untuk menangkap query struktur lama
- Semua aplikasi dependen, batch job, dan laporan yang diketahui telah diidentifikasi dan diperbarui
- Lingkungan staging telah diuji dengan akses baca struktur lama dicabut
- Rencana gradual cutover sudah ditentukan: instance atau region mana yang beralih terlebih dahulu
- Dashboard monitoring sudah disiapkan untuk mendeteksi error baca atau inkonsistensi data setelah cutover
- Rencana komunikasi sudah siap: siapa yang perlu tahu tentang cutover dan kapan
Intisari
Cutover adalah momen ketika pola migrasi Anda berhenti menjadi teoretis dan mulai memengaruhi pengguna nyata. Jangan perlakukan ini sebagai perubahan kode sederhana. Perlakukan sebagai event produksi yang membutuhkan monitoring, verifikasi, dan jalur rollback yang jelas. Satu hari ekstra yang Anda habiskan untuk memastikan tidak ada dependensi tersembunyi jauh lebih berharga daripada satu jam yang mungkin Anda hemat dengan terburu-buru menghapus struktur lama.