Mengapa Deployment Database Tidak Bisa Disamakan dengan Deployment Aplikasi

Bayangkan Anda menjalankan situs e-commerce di tengah sore yang sibuk. Pengguna sedang menjelajahi produk, menambahkan barang ke keranjang, dan melakukan checkout. Sementara itu, tim database Anda menjalankan migrasi untuk menambahkan kolom discount_price ke tabel products. Tiba-tiba, situs melambat drastis. Pencarian produk timeout. Checkout gagal. Pengguna mulai mengeluh di media sosial.

Apa yang terjadi? Database mengunci tabel products saat mengubah strukturnya, dan setiap query yang perlu membaca atau menulis data produk harus mengantre. Aplikasi itu sendiri baik-baik saja. Server dalam kondisi sehat. Tapi database sibuk melindungi dirinya dari korupsi data selama perubahan skema.

Skenario ini terjadi di tim yang memperlakukan deployment database sama seperti deployment aplikasi. Perbedaannya mendasar: Anda bisa menghentikan aplikasi, menggantinya dengan versi baru, dan memulai ulang dalam hitungan detik. Database harus terus melayani pengguna sambil berubah.

Bagaimana Lock Bekerja dan Mengapa Berbahaya

Saat Anda menjalankan perintah untuk mengubah struktur tabel, database perlu menjamin bahwa tidak ada operasi lain yang memodifikasi data yang sama selama perubahan berlangsung. Inilah cara database menjaga konsistensi. Untuk memastikannya, database mengakuisisi lock pada tabel atau baris tertentu. Selama lock aktif, query lain yang mencoba membaca atau menulis data di tabel yang sama harus menunggu.

Beberapa perubahan skema berlangsung cepat. Menambahkan kolom dengan nilai default NULL di PostgreSQL, misalnya, bisa selesai dalam milidetik tanpa memblokir pembacaan. Tapi operasi lain tidak begitu ramah. Membuat indeks pada tabel besar, mengubah tipe data kolom, atau menghapus kolom bisa mengunci tabel selama menit atau bahkan jam.

Perhatikan perbedaan antara dua pernyataan SQL ini:

-- Aman: menambahkan kolom nullable, selesai dalam milidetik, tanpa lock
ALTER TABLE products ADD COLUMN discount_price DECIMAL(10,2);

-- Berbahaya: menulis ulang seluruh tabel, mengunci selama menit pada tabel besar
ALTER TABLE products ALTER COLUMN price TYPE DECIMAL(12,2);

Pernyataan pertama menambahkan kolom yang bisa NULL, jadi database hanya memperbarui metadata. Pernyataan kedua mengubah tipe data kolom yang sudah ada, memaksa database menulis ulang setiap baris di tabel. Selama penulisan ulang berlangsung, tabel terkunci, dan semua query terhadap products harus menunggu.

Bahaya sesungguhnya adalah efek kaskade. Sebuah query yang menunggu lock tidak hanya memperlambat satu fitur. Ia bisa memblokir query lain yang bergantung pada tabel yang sama. Dalam kasus ekstrem, aplikasi berhenti merespons sama sekali karena semua thread database habis dipakai oleh query yang menunggu lock. Pengguna melihat loading spinner tak berujung atau error timeout. Dari sudut pandang pengguna, aplikasi mati. Database hanya sibuk melindungi dirinya sendiri.

Tidak Semua Perubahan Skema Sama

Database yang berbeda menangani lock secara berbeda, dan tidak semua operasi skema membawa risiko yang sama. Memahami operasi mana yang aman dan mana yang berbahaya sangat penting untuk merencanakan deployment database.

PostgreSQL dapat menambahkan kolom dengan default NULL tanpa memblokir pembacaan. Operasi DDL ONLINE MySQL dapat berjalan tanpa mengunci tabel untuk DML konkuren, tetapi tetap memerlukan lock metadata singkat di awal dan akhir. Bahkan operasi yang mengklaim "online" atau "zero-downtime" perlu diuji di lingkungan yang mirip produksi.

Operasi yang biasanya paling bermasalah:

  • Membuat indeks pada tabel besar
  • Mengubah tipe data kolom
  • Menghapus kolom
  • Menambahkan kolom dengan nilai default non-null (di beberapa database)
  • Mengganti nama kolom atau tabel
  • Menjalankan pernyataan ALTER TABLE yang menulis ulang seluruh tabel

Operasi yang umumnya lebih aman:

  • Menambahkan kolom dengan default NULL (di PostgreSQL)
  • Menambahkan indeks dengan CONCURRENTLY (di PostgreSQL)
  • Membuat tabel baru
  • Menambahkan kolom baru dengan DDL ONLINE (di MySQL, untuk operasi yang didukung)

Kuncinya adalah mengetahui kategori mana yang sesuai untuk setiap operasi di sistem database spesifik Anda, dan menguji waktu eksekusi aktual di lingkungan staging sebelum menjalankannya di produksi.

Mengapa Rollback Lebih Sulit dari yang Anda Kira

Rollback aplikasi itu mudah. Anda deploy versi kode sebelumnya, dan aplikasi mulai melayani permintaan dengan logika lama. Rollback database tidak seperti itu.

Jika Anda menambahkan kolom dan perlu rollback, Anda tidak bisa begitu saja "undeploy" kolom tersebut. Anda harus menjalankan migrasi lain untuk menghapusnya. Operasi penghapusan itu sendiri mungkin mengunci tabel. Jika migrasi mengubah tipe data atau merestrukturisasi tabel, rollback mungkin memerlukan konversi data kembali ke format lama, yang bisa lambat dan berisiko.

Asimetri ini mengubah cara Anda berpikir tentang risiko. Dengan aplikasi, Anda bisa deploy cepat dan rollback jika ada yang salah. Dengan database, Anda perlu mencegah masalah sejak awal, karena jalur pemulihannya menyakitkan.

Strategi Praktis untuk Deployment Database yang Lebih Aman

Tim yang menangani deployment database dengan baik tidak mengandalkan keberuntungan. Mereka membangun proses yang mengurangi kemungkinan insiden terkait lock dan membuat pemulihan dapat dikelola saat terjadi masalah.

Jadwalkan migrasi di periode lalu lintas rendah. Menjalankan perubahan skema jam 2 siang hari Selasa adalah undangan masalah. Jadwalkan jam 2 pagi hari Minggu, atau jendela lalu lintas rendah lainnya yang dimiliki aplikasi Anda. Jika aplikasi Anda melayani pengguna global, Anda mungkin perlu memecah migrasi menjadi langkah-langkah kecil yang bisa berjalan di beberapa jendela lalu lintas rendah.

Pecah perubahan besar menjadi langkah kecil. Alih-alih satu migrasi yang menambahkan tiga kolom, membuat dua indeks, dan mengubah tipe data, pisahkan menjadi migrasi terpisah. Setiap migrasi harus cukup kecil sehingga bisa selesai cepat dan di-rollback tanpa efek kaskade.

Ukur waktu eksekusi di staging. Sebelum menjalankan migrasi di produksi, jalankan di lingkungan staging yang memiliki volume data dan pola lalu lintas serupa. Jika migrasi memakan waktu 30 detik di staging, mungkin memakan waktu 30 menit di produksi dengan data nyata. Ukur dan rencanakan sesuai.

Pantau waktu tunggu lock selama migrasi. Siapkan alert yang terpicu saat query mulai menunggu lock lebih dari beberapa detik. Jika Anda melihat waktu tunggu lock meningkat, Anda perlu prosedur untuk membatalkan migrasi sebelum menyebabkan downtime penuh.

Miliki prosedur pembatalan yang jelas. Tentukan dengan tepat apa yang harus dilakukan jika migrasi terlalu lama atau menyebabkan kontensi lock. Ini bisa berarti mematikan proses migrasi, rollback ke versi skema sebelumnya, atau beralih ke read replica sementara migrasi selesai.

Checklist Praktis untuk Deployment Database

Sebelum menjalankan perubahan skema di produksi, lalui checklist ini:

  • Apakah operasi ini aman untuk pembacaan dan penulisan konkuren di sistem database Anda?
  • Sudahkah Anda menguji migrasi di lingkungan staging dengan volume data serupa?
  • Berapa perkiraan waktu eksekusi berdasarkan pengujian staging?
  • Apakah migrasi dijadwalkan selama jendela lalu lintas rendah?
  • Apakah Anda memiliki rencana rollback yang tidak memerlukan migrasi berisiko lain?
  • Apakah alert monitoring dikonfigurasi untuk waktu tunggu lock?
  • Apakah tim mengetahui prosedur pembatalan jika terjadi kesalahan?

Perbedaan Inti

Deployment aplikasi adalah tentang menukar kode. Deployment database adalah tentang mentransformasi data langsung sambil melayani pengguna. Ini adalah operasi yang fundamental berbeda yang memerlukan strategi berbeda, penilaian risiko berbeda, dan rencana rollback berbeda.

Tim yang sukses dengan deployment database adalah mereka yang menghormati perbedaan ini. Mereka tidak sekadar menempelkan langkah migrasi ke pipeline yang sama dengan deployment kode aplikasi. Mereka merancang alur kerja terpisah dengan pengaman yang sesuai, prosedur pengujian, dan monitoring.

Lain kali Anda merencanakan perubahan database, mulailah dengan bertanya: "Apa yang terjadi pada pengguna saat migrasi ini berjalan?" Jawaban atas pertanyaan itu akan memberi tahu Anda apakah Anda siap untuk deploy.