API order service kami mulai menunjukkan respons yang lambat dan data order yang kadang tidak sinkron dengan sumber utama setelah terjadi spike lalu lintas. Dari log dan metrik langsung terlihat bahwa cache Redis yang seharusnya mempercepat respons terus mengalami expired sebelum data baru dipopulasikan, sehingga klien terjebak menunggu fetch ulang. Artikel ini menguraikan investigasi dari gejala sampai perbaikan untuk mencegah cache Redis expired yang merusak SLA.
Konteks Sistem API Order
Order service adalah bagian dari arsitektur microservice dengan pola CQRS: data order disimpan pada database utama, kemudian diambil melalui read replica untuk kebutuhan API. Agar latency rendah, setiap permintaan GET order mencoba membaca dari cache Redis yang menyimpan payload JSON lengkap dengan TTL sekitar 30 detik.
Request flow sederhana:
- API menerima permintaan detail order.
- Service mengecek Redis: jika ada entry, langsung dikembalikan.
- Jika cache miss, service query database, kemudian menyimpan hasilnya ke Redis dengan expire.
Biasanya pola ini berhasil karena traffic membaca order relatif stabil. Namun saat ada promosi flash sale, volume spike membuat TTL menjadi titik kegagalan.
Gejala, Log, dan Metrik
Gejala awal yang dilaporkan tim produk adalah:
- Respons API order berlangsung > 500 ms padahal biasanya < 150 ms.
- Beberapa API mengembalikan order kosong padahal data sudah ada di database.
- Spike error 5xx akibat timeout downstream.
Jejak log menunjukkan pola berikut:
- Cache hit ratio turun drastis pada periode spike, sementara throughput Redis tetap tinggi.
- Log middleware mencatat banyak
cache missberuntun untuk key yang sama. - Log worker yang memuat data ke cache menyatakan set berhasil tapi diikuti oleh
expireevent segera.
Metrik latency Redis meningkat karena banyak klien menunggu fetch ulang. Grafik TTL bucket dari observabilitas Redis menunjukkan baris angka TTL mendekati nol setiap beberapa detik, yang mengindikasikan TTL ditetapkan terlalu pendek atau tidak di-refresh dengan benar.
Analisis Root Cause: Cache Redis Expired
Setelah menelusuri token request, root cause teridentifikasi sebagai berikut:
- TTL sebesar 30 detik terlalu pendek untuk periode spike; banyak permintaan ke key yang sama terjadi dalam jarak waktu lebih singkat, sehingga cache resmi expired sebelum terdapat kesempatan untuk cache hit berikutnya.
- Race condition saat cache miss membuat beberapa worker memanggil database secara bersamaan, menambah beban dan memicu lebih banyak TTL set ulang.
- Expired event memicu fallback synchronous ke database tanpa mekanisme grace period atau provisioning ulang otomatis.
Penyebab utamanya bukan Redis bermasalah, melainkan konfigurasi TTL tidak disesuaikan dengan pola traffic. Selain itu tidak ada strategi fallback yang menangani cache miss dalam jumlah besar.
Langkah Perbaikan
1. Penyesuaian TTL Berdasarkan Pola Traffic
TTL harus reflektif terhadap bobot request. Kami menaikkan TTL menjadi 2 menit dengan pendekatan adaptive, yakni jika jumlah hit per key melebihi threshold, TTL di-refresh menggunakan EXPIRE tanpa harus re-set data. Contoh implementasi:
// pseudo-code untuk memperpanjang TTL jika cache masih valid
const KEY = `order:${orderId}`;
const cached = await redis.get(KEY);
if (cached) {
await redis.expire(KEY, 120); // refresh TTL jika request padat
return JSON.parse(cached);
}
Perpanjangan ini diterapkan hanya jika data masih dianggap relevan; untuk order yang berubah sering (misalnya status update), TTL tetap pendek tapi disinkronisasi dari event source.
2. Fallback Data Saat Cache Miss Besar
Kami menambahkan circuit breaker ringan yang:
- Mendeteksi lonjakan cache miss per key (misal > 5 dalam 5 detik).
- Menunda fetch database selama 50 ms dan hanya satu worker yang mengambil data.
- Worker lain menggunakan nilai fallback sementara (misalnya cache copy yang sedikit usang) atau mengirim
503dengan headerRetry-Afteruntuk mencegah thundering herd.
Implementasi fallback dapat memanfaatkan Redis Streams atau key supplemental yang berisi data snapshot lama untuk response cepat saat data terbaru belum tersedia.
3. Observabilitas untuk TTL dan Cache Behavior
Perbaikan TTL tidak lengkap tanpa monitoring yang memadai. Kami menambahkan instrumen berikut:
- Histogram latency Redis per endpoint, agar bisa melihat dampak cache hit versus DB hit.
- Counter untuk
cache miss,cache refresh, dancache expire. - Trace distributed request untuk menunjukkan alur saat cache miss menyebabkan timeout downstream.
Alert diatur jika cache miss meningkat lebih dari 30% dalam 5 menit beruntun, atau latency Redis melebihi 250 ms.
Pelajaran bagi Developer
Beberapa pelajaran penting dari studi kasus ini:
- TTL tidak boleh statis ketika traffic memiliki pola burst; TTL yang terlalu pendek menyebabkan cache menjadi sumber ketidakstabilan.
- Jaga fallback untuk mencegah sistem menjadi tidak responsif saat cache tidak tersedia — penanganan thundering herd adalah kebutuhan, bukan kemewahan.
- Observabilitas mempermudah diagnosis; tanpa metrik TTL, kita hanya melihat gejala, bukan parameter yang sebenarnya salah.
Dengan menggabungkan penyesuaian TTL, fallback yang cerdas, dan observabilitas lengkap, API order service kembali ke SLA-nya dan lebih tahan terhadap beban mendadak.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!