Studi Kasus: Membongkar Kasus API Melambat Tanpa Deployment, Lonjakan Network I/O Database
4 min read

Studi Kasus: Membongkar Kasus API Melambat Tanpa Deployment, Lonjakan Network I/O Database

Studi Kasus

Hari Jumat, pukul 17.00. Waktu yang seharusnya menjadi penutup minggu kerja.

Namun PagerDuty berbunyi.

Laporan awal menunjukkan kondisi yang membingungkan:

  • Waktu respon API melonjak dari ±200 ms menjadi ±8 detik
  • CPU normal di seluruh instance
  • Memory normal
  • Tidak ada deployment atau perubahan konfigurasi
  • Query database tampak berjalan normal
  • Masalah dimulai tepat 47 menit yang lalu
  • Satu anomali mencolok: Network I/O pada primary database melonjak tajam di waktu yang sama

Ini bukan insiden biasa. Ini adalah kasus klasik yang menuntut pendekatan analitis, bukan asumsi.


Langkah Pertama: Membaca Sinyal, Jangan Menebak

Kesalahan paling umum saat on-call adalah langsung menebak penyebab berdasarkan pengalaman masa lalu.

Namun pada kasus ini, data berbicara cukup jelas.

Mari kita eliminasi kemungkinan satu per satu.


Apa yang Tidak Terjadi

Berdasarkan metrik:

  • Bukan CPU-bound problem → CPU tetap rendah
  • Bukan memory leak / GC pressure → memory stabil
  • Bukan regresi deployment → tidak ada perubahan kode
  • Bukan query lambat secara komputasi → eksekusi query tampak normal

Artinya, bottleneck bukan pada komputasi.

Jika bukan komputasi, maka yang tersisa adalah I/O.


Satu Sinyal yang Berteriak: Network I/O Database

Lonjakan tajam pada network I/O database adalah petunjuk paling penting.

Ini menandakan satu hal:

Database sedang mengirim data jauh lebih banyak dari biasanya.

Bukan membaca. Bukan menghitung. Tapi mengirim.


Diagram Alur Request–Database–Network

Untuk memahami masalah ini dengan cepat, berikut diagram teks yang menggambarkan alur request normal vs saat insiden terjadi.

Kondisi Normal

[ Client ]
     |
     v
[ API Service ]
     |
     |  (Query kecil + LIMIT)
     v
[ Database ] --(hasil data kecil)--> [ API Service ] --> Response cepat (~200 ms)

Pada kondisi normal:

  • Database mengeksekusi query dengan cepat
  • Data yang dikirim relatif kecil
  • Network tidak menjadi bottleneck

Kondisi Saat Insiden

[ Client ]
     |
     v
[ API Service ]
     |
     |  (Query tanpa LIMIT / dataset besar)
     v
[ Database ] --(puluhan/ratusan MB data)---------------------->
                 ^                                          |
                 |------ Network saturated / antre ---------|

[ API Service ] menunggu fetch data selesai
Response baru terkirim setelah 8 detik

Pada kondisi ini:

  • Eksekusi query tetap cepat
  • Namun transfer data memakan waktu lama
  • API thread/goroutine idle sambil menunggu network

Diagram ini menjelaskan mengapa CPU rendah, tapi latency tinggi.


Hipotesis Utama: Query Menghasilkan Dataset Sangat Besar

Hipotesis paling masuk akal:

Ada query (atau sekumpulan query) yang tiba-tiba menghasilkan hasil data dalam jumlah sangat besar, sehingga waktu transfer jaringan mendominasi total response time.

Ini menjelaskan seluruh gejala:

  • Query bisa selesai cepat (CPU rendah)
  • Namun aplikasi menunggu lama saat fetch rows
  • API terlihat lambat meskipun database tidak “sibuk”

Mengapa Masalah Ini Sulit Terdeteksi?

Karena banyak engineer hanya melihat:

  • Query execution time
  • Index usage
  • Explain plan

Padahal:

Execution cepat tidak berarti response cepat jika ukuran data besar.

Contoh sederhana:

SELECT * FROM orders WHERE status = 'PAID';

Query ini bisa dieksekusi sangat cepat, tetapi jika mengembalikan ratusan ribu baris, waktu transfer bisa mencapai beberapa detik.


Petunjuk Waktu: Mengapa Tepat 47 Menit Lalu?

Masalah yang muncul tepat di menit tertentu hampir selalu disebabkan oleh sistem terjadwal, bukan manusia.

Kemungkinan yang perlu dicurigai:

  • Cron job internal
  • Scheduled report / export data
  • Cache TTL yang habis serentak
  • Background worker yang aktif berkala

Tidak ada deploy, tapi perilaku sistem berubah.


Pola Umum Penyebab di Lapangan

Dari pengalaman produksi, penyebab paling sering adalah:

Pagination atau LIMIT yang Hilang

Sebelumnya:

SELECT * FROM users ORDER BY created_at DESC LIMIT 50;

Tanpa disadari berubah menjadi:

SELECT * FROM users ORDER BY created_at DESC;

Dampaknya bukan CPU, tapi network saturation.

Cache Miss Storm

  • Cache expired bersamaan
  • Semua request menembus database
  • Query yang sama mengirim data besar berulang kali

Network I/O database naik drastis, meski query cepat.

Scheduled Export atau Integrasi Eksternal

  • BI tool
  • Data sync partner
  • Admin export CSV

Semua ini sering:

  • Tidak tercatat sebagai deployment
  • Mengakses database secara langsung
  • Menarik data dalam jumlah besar

Langkah Investigasi Teknis yang Tepat

Cari Query dengan Jumlah Rows Terbesar

Fokus bukan pada durasi, tapi jumlah data.

Contoh pada PostgreSQL:

SELECT query, calls, rows
FROM pg_stat_statements
ORDER BY rows DESC
LIMIT 10;

Bandingkan dengan baseline historis.

Pecah Waktu di APM / Tracing

Perhatikan perbedaan:

  • Query execution time
  • Fetch / transfer time

Pola khas:

Execution: 40 ms
Fetch / Network: 7.8 s

Ini konfirmasi bahwa bottleneck ada di transfer data.

Audit Job Terjadwal

Cari proses yang:

  • Aktif di menit yang sama
  • Mengakses tabel besar
  • Tidak melalui API utama

Mitigasi Cepat Saat Insiden

Jika insiden masih berlangsung:

  • Terapkan hard limit pada hasil query
  • Batasi ukuran response API
  • Hentikan sementara job export
  • Tambahkan rate limit pada endpoint sensitif

Tujuannya bukan sempurna, tapi menstabilkan sistem.


Pelajaran Arsitektural

Kasus ini mengajarkan hal penting:

  • Monitoring tidak boleh hanya fokus ke CPU dan memory
  • Ukuran data dan network I/O adalah first-class metric
  • Query yang “cepat” tetap bisa melumpuhkan sistem

Kesimpulan

Ketika:

  • API lambat
  • CPU dan memory normal
  • Tidak ada deployment
  • Network I/O database melonjak

Maka pertanyaan utama bukan:

“Query apa yang lambat?”

Melainkan:

“Siapa yang menarik data terlalu banyak?”

Dan sering kali, jawabannya tersembunyi di balik query yang terlihat sangat biasa.

Kasus ini bukan tentang bug rumit — tapi tentang memahami bagaimana data bergerak di sistem terdistribusi.