Deploy dan migrasikan dengan aman
Periode kompatibilitas, migrasi expand/contract, canary, batas rollback, dan cutover berbasis bukti.
Pertanyaan
Gimana kita mengubah kode dan skema yang lagi dipakai tanpa merusak user, dan kapan perubahan itu masih bisa dibatalkan?
Setelah baca ini, kamu bisa memecah perubahan skema jadi langkah yang kompatibel, merancang canary dengan kriteria berhenti, dan nentuin titik di mana rollback nggak lagi aman.
Prasyarat dan contoh
Kamu sudah paham replikasi dan model data (modul sebelumnya), serta SLI dan anggaran error di M16.01. Canary butuh metrik yang bisa dibandingin, jadi lesson itu dipakai di sini.
Contoh: kamu mau ganti kolom nama di tabel pengguna jadi nama_depan dan nama_belakang.
Rilis naif: migrasi skema dan deploy kode baru bersamaan. Selama deploy bergulir 6 instance,
beberapa instance masih kode lama yang menulis nama, sementara kolom itu sudah hilang. Hasilnya
error 500 selama beberapa menit, dan rollback kode nggak mengembalikan kolom yang sudah dihapus.
Mekanisme
Dalam deploy bergulir, versi lama dan baru berjalan bersamaan, dan data ditulis oleh keduanya. Karena itu setiap perubahan harus kompatibel mundur dan maju selama periode kompatibilitas.
Expand/contract (parallel change) memecah perubahan skema jadi langkah yang masing-masing aman dibatalkan:
- Expand. Tambah kolom
nama_depan,nama_belakang(nullable). Kode lama nggak terpengaruh. - Dual write. Deploy kode yang menulis ke kolom lama dan baru. Masih membaca kolom lama.
- Backfill. Salin data lama ke kolom baru dalam batch kecil (mis. 1.000 baris per batch dengan jeda), supaya nggak mengunci tabel atau memenuhi replikasi. Verifikasi jumlah dan checksum.
- Pindah baca. Deploy kode yang membaca kolom baru. Masih dual write supaya rollback aman.
- Contract. Setelah satu siklus rilis tanpa masalah, berhenti menulis kolom lama, lalu hapus kolom di rilis terpisah.
Backfill 100 juta baris pada 1.000 baris per 200 ms = 100.000 batch × 0,2 detik ≈ 5,5 jam. Itu normal. Kecepatan jarang jadi tujuan, keamanan yang jadi tujuan.
Canary mengirim sebagian kecil trafik (mis. 1%, lalu 5%, 25%, 100%) ke versi baru dan membandingkan SLI-nya dengan versi lama. Tentukan kriteria berhenti sebelum rilis: "rollback otomatis kalau error rate canary lebih dari 2× baseline atau p99 naik lebih dari 30% selama 10 menit". Tiap tahap butuh trafik cukup supaya perbandingan bermakna: 1% dari 50 request/detik cuma 0,5 request/detik, terlalu sedikit buat mendeteksi error 1%.
Batas rollback adalah titik di mana kembali ke versi lama nggak lagi memulihkan sistem. Contohnya: versi baru sudah menulis format data yang nggak bisa dibaca versi lama, atau migrasi destruktif sudah jalan. Sebelum titik itu, rollback itu murah. Sesudahnya, satu-satunya jalan adalah maju (roll forward) dengan perbaikan. Tulis titik itu di runbook rilis.
Cutover berbasis bukti untuk perpindahan besar (database baru, layanan baru): jalankan jalur baru dalam mode bayangan, bandingkan hasilnya dengan jalur lama (mis. 99,99% respons identik dalam 7 hari), pindahkan baca dulu, baru tulis. Pindah tulis pakai satu titik pindah yang bisa dibalik selama bukti belum cukup.
Saat rancangan ini gagal
- Migrasi dan kode dirilis bersamaan. Selama periode bergulir, salah satu versi pasti bertemu skema yang nggak dikenalnya.
- Migrasi yang mengunci tabel.
ALTER TABLEyang menulis ulang tabel 200 GB bisa memblokir tulis berjam-jam di beberapa engine. Pakai varian online atau tabel baru plus backfill. - Backfill yang membanjiri replikasi. Lag replika naik dan pembacaan dari replika jadi basi. Pantau lag dan sesuaikan kecepatan batch.
- Canary tanpa kriteria berhenti. Orang melihat dashboard dan berdebat "kayaknya baik-baik saja". Keputusan yang diambil saat panik biasanya terlambat.
- Canary yang nggak mewakili. Trafik canary cuma dari satu region atau segmen. Bug di segmen lain lolos.
- Rollback yang belum pernah dicoba. Skrip rollback yang baru dijalankan saat insiden sering gagal karena dependensi yang berubah.
- Menghapus kolom terlalu cepat. Job batch mingguan masih membaca kolom lama, dan baru ketahuan seminggu kemudian.
Contoh tandingan: expand/contract menambah biaya (dua kolom, dual write, beberapa rilis). Buat tabel kecil dengan jendela pemeliharaan yang disepakati dan nol dependen, migrasi satu langkah bisa lebih sederhana dan cukup aman.
Latihan
Kamu perlu mengubah harga (integer rupiah) jadi harga_sen (integer, ×100) di tabel produk
berisi 40 juta baris. Layanan jalan di 12 instance dengan deploy bergulir. Ada job laporan
harian yang membaca harga.
- Tulis urutan rilisnya.
- Berapa lama backfill kalau 2.000 baris per batch dan 150 ms per batch?
- Tentukan satu kriteria berhenti canary dan satu titik batas rollback.
Lihat pembahasan
- Urutan:
- Expand: tambah kolom
harga_sennullable. - Deploy kode dual write: tulis
hargadanharga_sen = harga × 100. - Backfill baris lama, verifikasi
harga_sen = harga × 100untuk semua baris. - Ubah job laporan dan kode baca ke
harga_sen. Tetap dual write. - Setelah satu siklus laporan harian tanpa masalah, hentikan tulis
harga. - Rilis terpisah: hapus kolom
harga.
- Expand: tambah kolom
- 40.000.000 / 2.000 = 20.000 batch × 0,15 detik = 3.000 detik, sekitar 50 menit, belum termasuk jeda dan pelambatan karena lag replika. Rencanakan sekitar 1 sampai 2 jam.
- Kriteria berhenti: rollback otomatis kalau error rate canary lebih dari 2× baseline atau
selisih total pesanan (jumlah × harga) antara canary dan baseline lebih dari 0,5% selama 15
menit. Batas rollback: begitu tulis
hargadihentikan (langkah 5), kode lama yang membacahargaakan melihat data basi. Sebelum itu rollback aman. Sesudahnya, maju saja.
Job laporan adalah dependen yang mudah terlupa. Inventaris pembaca kolom sebelum langkah 6.
Terkait
- M16.01 Ukur perjalanan pengguna memberi SLI buat kriteria canary.
- M16.04 Lakukan pemulihan, bukan sekadar berasumsi menjaga jaring pengaman kalau migrasi merusak data.
- M16.06 Tangani insiden dan tinjau rancangan membahas respons kalau rilis memicu insiden.
Catatan
- Asumsi: deploy bergulir dengan kedua versi hidup bersamaan, dan engine database mendukung penambahan kolom nullable tanpa menulis ulang tabel (mis. PostgreSQL modern).
- Waktu backfill adalah perkiraan, bukan jaminan. Ukur di staging dengan data berukuran serupa.
- Yang nggak dibahas: migrasi lintas database, blue/green skala besar, dan perubahan skema di sistem event yang disimpan tanpa batas waktu.
- Terakhir ditinjau: 26 Oktober 2026.