Menguji Migrasi Database Sebelum Diterapkan ke Produksi
Anda telah menulis skrip migrasi. Tampaknya benar. Sintaksnya valid. Logikanya terasa tepat. Anda menjalankannya di database lokal, dan semuanya berjalan lancar. Kemudian Anda menerapkannya ke produksi, dan semuanya rusak.
Tabel tersebut memiliki jutaan baris. Database lokal Anda hanya memiliki dua belas baris. Migrasi menambahkan kolom NOT NULL, tetapi produksi memiliki nilai NULL yang tidak Anda ketahui. ALTER TABLE mengunci operasi tulis selama lima belas menit di tengah lalu lintas puncak.
Skenario ini tidak jarang terjadi. Ini terjadi karena lingkungan tempat Anda menguji migrasi tidak cocok dengan lingkungan tempat migrasi akan benar-benar berjalan. Migrasi yang berhasil di database kosong atau tidak cocok memberikan keyakinan palsu. Perbaikannya bukanlah menguji lebih hati-hati di mesin lokal Anda. Perbaikannya adalah membangun lingkungan pengujian yang mencerminkan realitas produksi.
Mengapa Skema yang Cocok Itu Penting
Skrip migrasi ditulis berdasarkan asumsi. Skrip tersebut mengasumsikan kolom tertentu ada, indeks tertentu tersedia, batasan tertentu sudah terpasang. Jika database pengujian Anda memiliki skema yang berbeda, Anda menguji berdasarkan kumpulan asumsi yang berbeda.
Pertimbangkan migrasi yang menambahkan kolom NOT NULL. Di database pengujian dengan tabel kosong, migrasi berjalan seketika. Di produksi, tabel memiliki baris dengan nilai NULL di kolom tersebut. Migrasi gagal, dan sekarang Anda mengalami insiden produksi.
Cara paling andal untuk mencocokkan skema adalah dengan mengambil dump skema dari produksi dan mengembalikannya ke lingkungan pengujian Anda. Ini memberi Anda struktur tabel, indeks, batasan, dan tipe data yang persis sama dengan yang ada di produksi. Anda tidak lagi menebak-nebak apakah skema pengujian Anda cocok dengan kenyataan.
Berikut adalah contoh konkret menggunakan PostgreSQL:
# Dump hanya skema (tanpa data) dari produksi
pg_dump --schema-only --no-owner --no-acl production_db > schema.sql
# Kembalikan skema ke database pengujian Anda
psql test_db < schema.sql
Data yang Mengekspos Masalah Nyata
Tabel kosong atau tabel dengan data uji acak tidak akan mengungkapkan kasus tepi. Kegagalan migrasi sering kali berasal dari data yang ada di produksi tetapi tidak ada di kumpulan pengujian Anda.
Jika migrasi Anda mengubah tipe kolom, data uji Anda harus menyertakan nilai tepi: string panjang, angka desimal dengan banyak digit, nilai NULL di kolom tersebut. Jika migrasi Anda menambahkan batasan unik, data uji Anda harus menyertakan baris duplikat yang melanggar batasan tersebut. Jika migrasi Anda menghapus kolom, data uji Anda harus menyertakan kueri yang masih mereferensikan kolom tersebut.
Anda tidak perlu menyalin seluruh dataset produksi. Untuk tabel dengan jutaan baris, beberapa ribu baris yang dipilih dengan baik sudah cukup untuk membuat mesin database menghasilkan rencana eksekusi yang realistis. Tujuannya bukan untuk mereplikasi volume produksi. Tujuannya adalah untuk mereplikasi pola data yang dapat menyebabkan migrasi berperilaku berbeda.
Dry-Run sebagai Jaring Pengaman
Dry-run mengeksekusi SQL migrasi tanpa mengubah database secara permanen. Beberapa alat migrasi memiliki mode dry-run bawaan. Jika alat Anda tidak memilikinya, Anda dapat membungkus migrasi dalam sebuah transaksi dan melakukan rollback di akhir.
Tujuan dry-run bukan untuk memastikan bahwa migrasi berhasil. Tujuannya adalah untuk melihat peringatan, kesalahan, dan perubahan rencana eksekusi yang mungkin mengindikasikan masalah. Migrasi yang berjalan lancar di tabel kecil mungkin menunjukkan peringatan pemindaian tabel penuh saat dijalankan terhadap skema yang realistis. ALTER TABLE pada tabel besar mungkin menunjukkan perkiraan waktu eksekusi yang tidak dapat diterima untuk jendela pemeliharaan Anda.
Setelah dry-run, tinjau output secara manual atau melalui pemeriksaan otomatis. Cari operasi yang dapat mengunci tabel untuk waktu yang lama. Cari kueri yang dapat menurunkan kinerja. Cari perilaku tak terduga yang tidak muncul selama pengujian lokal.
Simulasi Beban Ringan Selama Migrasi
Beberapa migrasi aman di database yang tidak aktif tetapi menyebabkan masalah di bawah lalu lintas nyata. ALTER TABLE yang memperoleh kunci mungkin selesai dalam hitungan detik ketika tidak ada orang lain yang menggunakan tabel. Di bawah beban produksi, kunci yang sama dapat menyebabkan waktu tunggu kueri habis dan kesalahan aplikasi.
Anda tidak perlu pengujian beban penuh. Skrip sederhana yang menjalankan kueri SELECT dan INSERT terhadap tabel yang terpengaruh selama migrasi sudah cukup. Jika kueri simulasi tersebut gagal atau waktu tunggunya habis, Anda telah menemukan masalah yang akan menimpa pengguna produksi.
Jalankan simulasi ini selama fase dry-run. Jika migrasi menyebabkan deadlock atau waktu tunggu yang berlebihan di bawah beban ringan, Anda perlu mempertimbangkan kembali pendekatan Anda. Mungkin Anda perlu menggunakan strategi penguncian yang tidak terlalu mengganggu. Mungkin Anda perlu memecah migrasi menjadi langkah-langkah yang lebih kecil. Mungkin Anda perlu menjadwalkannya selama jendela lalu lintas yang lebih rendah.
Mengotomatiskan Lingkungan Pengujian
Menyiapkan lingkungan pengujian secara manual untuk setiap migrasi itu lambat dan rawan kesalahan. Pendekatan yang lebih baik adalah mengotomatiskannya sebagai bagian dari pipeline CI Anda.
Ketika migrasi baru dikomit, pipeline membuat lingkungan pengujian dari snapshot skema produksi. Pipeline memuat data uji yang relevan. Pipeline menjalankan dry-run. Pipeline mensimulasikan beban ringan. Kemudian pipeline menghancurkan lingkungan tersebut.
Otomatisasi ini memastikan setiap migrasi diuji terhadap baseline yang konsisten. Tidak ada yang dapat melewatkan pengujian karena sedang terburu-buru. Tidak ada yang dapat mengklaim pengujian berhasil karena mereka menggunakan skema yang berbeda. Pipeline menerapkan kondisi yang sama setiap saat.
Daftar Periksa Praktis
Sebelum menjalankan migrasi di produksi, pastikan kondisi-kondisi ini terpenuhi:
- Skema pengujian sama persis dengan skema produksi
- Data uji mencakup kasus tepi yang relevan dengan migrasi
- Dry-run selesai tanpa peringatan atau kesalahan yang tidak terduga
- Simulasi beban ringan tidak menyebabkan kegagalan atau waktu tunggu habis
- Lingkungan pengujian dibuat dari snapshot produksi terbaru
Artinya bagi Pipeline Anda
Migrasi database tidak seperti kode aplikasi. Anda tidak bisa hanya menerapkan dan mengamati. Migrasi yang gagal dapat merusak data, mengunci tabel, dan menyebabkan waktu henti yang berkepanjangan. Biaya migrasi yang buruk jauh lebih tinggi daripada biaya rilis aplikasi yang buruk.
Menguji migrasi di lingkungan yang realistis bukanlah opsional. Inilah perbedaan antara mengetahui bahwa migrasi Anda akan berhasil dan berharap migrasi itu akan berhasil. Lingkungan yang Anda bangun untuk pengujian tidak perlu mahal atau rumit. Lingkungan itu harus representatif.
Mulailah dengan dump skema dari produksi. Tambahkan data uji yang ditargetkan. Jalankan dry-run. Simulasikan beban ringan. Otomatiskan seluruh proses. Database produksi Anda akan berterima kasih.