Notifikasi billing dari provider cloud biasanya kubuka belakangan, soalnya angkanya jarang berubah drastis. Bulan itu beda: dari Rp1,2 juta jadi Rp4,8 juta, empat kali lipat, padahal aku tidak merilis fitur baru sama sekali di tracker langgananku. Yang berubah cuma satu hal — agensi yang tiga minggu sebelumnya upgrade jadi klien tahunan terbesar mulai benar-benar memakai kursi tambahan mereka, dan tabel subscriptions tumbuh dari sekitar 50 ribu baris jadi hampir 400 ribu baris dalam waktu singkat.
Alarm yang Salah Kusalahkan ke Traffic
Reaksi pertamaku klasik: menyalahkan lonjakan traffic. Aku sempat berpikir jangan-jangan ini pengulangan insiden viral beberapa minggu lalu, jadi aku langsung cek dashboard request per menit. Ternyata traffic-nya biasa saja, cuma naik sekitar 15%. Yang melonjak justru CPU utilization instance database — rata-rata harian naik dari 20% ke 85%, kadang menyentuh 100% pas jam sibuk agensi itu login untuk melihat ringkasan klien mereka.
Aku hampir mengambil jalan pintas paling gampang: upgrade instance database ke tier lebih besar, bayar lebih mahal, masalah "hilang". Untungnya sebelum klik tombol upgrade, aku iseng buka query log slow query yang selama ini nyalanya cuma untuk formalitas dan hampir tidak pernah kubaca.
Satu Query yang Diam-Diam Full Table Scan
Log itu penuh satu pola: endpoint /dashboard/summary, yang dipanggil setiap kali agensi membuka halaman ringkasan klien mereka, menjalankan query yang memfilter tabel subscriptions berdasarkan client_id dan status. Aku jalankan EXPLAIN ANALYZE di query itu dan hasilnya bikin aku diam beberapa detik: Seq Scan on subscriptions, bukan Index Scan. Query itu memindai seluruh tabel setiap kali dipanggil, dan karena satu agensi sekarang punya puluhan klien yang masing-masing dibuka berkali-kali sehari oleh beberapa staf sekaligus, jumlah pemanggilan query itu ikut melonjak berlipat.
Waktu tabelnya masih 50 ribu baris, full table scan itu selesai dalam hitungan milidetik, tidak terasa sama sekali — makanya bertahun-tahun tidak ada yang komplain. Begitu baris bertambah delapan kali lipat, biaya scan itu ikut bertambah proporsional, dan karena query itu dipanggil ratusan kali per jam oleh satu klien besar saja, efeknya menumpuk jadi beban CPU yang terus-menerus tinggi — yang ujungnya ditagih sebagai jam compute ekstra oleh provider cloud.
Aku sempat malu sendiri karena kolom client_id dan status itu justru dua kolom yang paling sering dipakai untuk filter di hampir semua query penting aplikasi ini, tapi tidak ada satu pun index komposit untuk keduanya. Waktu bikin fitur ini dulu, tabelnya masih kosong, jadi index terasa seperti optimisasi prematur yang bisa ditunda — dan tertunda itu ternyata bertahan sampai sekarang.
Satu Migration, Bukan Upgrade Instance
Perbaikannya jauh lebih murah daripada upgrade instance yang tadinya hampir kuklik: satu migration menambahkan index komposit (client_id, status), dijalankan CONCURRENTLY supaya tidak mengunci tabel produksi saat proses berjalan. Prosesnya sekitar dua menit untuk 400 ribu baris. Setelah index aktif, aku jalankan ulang EXPLAIN ANALYZE yang sama: Index Scan, waktu eksekusi turun dari rata-rata 340ms jadi di bawah 4ms.
Dalam 24 jam setelah deploy, CPU utilization database turun kembali ke sekitar 12% rata-rata harian — lebih rendah dari sebelum insiden, karena aku juga sekalian menghapus satu query N+1 kecil yang ikut ketahuan di log yang sama. Tagihan bulan berikutnya kembali ke kisaran Rp1,3 juta. Aku tidak jadi upgrade instance, dan lebih penting lagi: aku sekarang tahu satu kelemahan struktural yang selama ini tidak kelihatan cuma karena skalanya masih kecil.
Yang membuatku sedikit gelisah bukan biayanya — Rp3,6 juta selisih itu masih bisa kutanggung sebulan — tapi soal apa yang akan terjadi kalau agensi itu bukan klien pertama yang menabrak limit ini, melainkan klien kelima atau kesepuluh yang tumbuh besar bersamaan. Skala kecil menyembunyikan banyak dosa desain, dan aku baru sadar itu setelah satu klien saja tumbuh cukup cepat untuk membukanya.
Takeaway
Query yang "aman" di skala kecil bukan berarti aman selamanya — index yang terasa seperti optimisasi prematur waktu tabel masih kosong bisa jadi utang teknis yang baru terlihat begitu satu klien besar tumbuh cukup cepat. Slow query log yang jarang dibaca ternyata lebih murah daripada upgrade instance yang jadi solusi pintas paling gampang. Kalau aku harus mengambil satu kebiasaan baru dari insiden ini, itu adalah menjadwalkan EXPLAIN ANALYZE rutin untuk setiap endpoint yang paling sering dipanggil klien terbesar, bukan menunggu sampai tagihan cloud yang memberitahuku duluan.
Sumber gambar: Christopher Gower di Unsplash Sumber gambar: Florian Olivo di Unsplash Sumber gambar: Ales Nesetril di Unsplash
The conversation 0
No comments yet. Start the conversation.