TTL, eviction (LRU/LFU), dan invalidation
Tiga cara data keluar dari cache: kedaluwarsa karena waktu, dibuang karena memori penuh, atau dihapus karena sumbernya berubah. Dan apa artinya "stale data"
Sebelumnya, lesson 0013 membahas di mana cache berada dan pola cache-aside, read-through, write-through, write-behind. Semua pola itu menyisakan satu pertanyaan: kapan salinan di cache berhenti dipakai? Lesson ini menjawabnya dengan tiga mekanisme yang sering tertukar di interview.
1. TTL: kedaluwarsa karena waktu
TTL (time to live) adalah umur maksimum satu entri. Di Redis, EXPIRE key detik memasang timeout; setelah lewat, key dihapus otomatis.
Redis menghapusnya dengan dua cara: pasif (saat key diakses dan ternyata sudah lewat waktunya) dan aktif (secara berkala menguji sejumlah key ber-TTL secara acak). [1]
Dokumentasi ElastiCache menambahkan TTL ke cache-aside maupun write-through: key yang kedaluwarsa diperlakukan seperti tidak ada, lalu database di-query lagi.
TTL "doesn't guarantee that a value isn't stale", tetapi menjaga data tidak terlalu basi. [2]
Di HTTP, TTL ditulis sebagai Cache-Control: max-age=N. RFC 9111 merumuskannya: respons masih segar (fresh) kalau
freshness_lifetime > current_age; lewat dari itu, respons menjadi stale. [3]
Memilih angkanya: Azure memperingatkan TTL terlalu pendek membuat aplikasi terus mengambil ulang dari data store, dan terlalu panjang membuat data basi; TTL harus mengikuti pola akses. [4] Cara mengucapkannya: "TTL = berapa lama bisnis rela melihat data lama". Harga flash sale: detik. Daftar kategori: jam.
2. Eviction: dibuang karena memori penuh
Cache lebih kecil dari database. Saat data melewati batas maxmemory, Redis menjalankan maxmemory-policy
untuk memilih key yang dibuang. [5] Yang perlu dikenal:
| Policy | Yang dibuang | Kapan dipakai |
|---|---|---|
noeviction | tidak ada; write baru mendapat error | Redis dipakai sebagai penyimpanan, bukan cache |
allkeys-lru | key yang paling lama tidak diakses (LRU, least recently used) | "good default" menurut dokumentasi Redis |
allkeys-lfu | key yang paling jarang diakses (LFU, least frequently used) | sebagian kecil key populer dalam waktu lama |
volatile-lru, volatile-ttl, … | hanya key yang punya TTL | cache dan data permanen di satu instance |
Kutipan tabel: [5]. Kebijakan volatile-* berperilaku seperti noeviction kalau tidak ada key ber-TTL.
LRU Redis adalah aproksimasi: ia mengambil sampel beberapa key (maxmemory-samples 5) lalu membuang yang paling lama tidak diakses [5];
LFU juga aproksimasi, memakai counter probabilistik dengan decay sehingga key yang dulu populer bisa turun peringkat. [5]
Jangan tertukar: TTL dipicu waktu dan berlaku per key. Eviction dipicu memori dan memilih korban dari banyak key. Key tanpa TTL tetap bisa di-evict oleh allkeys-*.
Latihan 1 — TTL dan eviction
Jawab tanpa scroll ke atas. Soal yang sama akan muncul lagi, diacak, di review 0019.
Kuis di lesson ini adalah feedback cepat, bukan bukti penguasaan; yang dicatat hanya hasil review 0019.
3. Invalidation dan stale data
Stale data adalah salinan di cache yang sudah berbeda dari sumbernya. Invalidation adalah tindakan menghapus atau menandai salinan itu supaya request berikutnya mengambil nilai baru. Cache tidak tahu kapan database berubah: perubahan di data store "doesn't appear in the cache until the item loads again". [4]
Alur invalidation yang benar dengan cache-aside:
Kalau urutannya dibalik (hapus cache dulu), ini yang bisa terjadi [4]:
Empat cara invalidation, dari yang termurah:
- TTL saja. Tanpa kode tambahan; data basi paling lama sebesar TTL. [2]
- Hapus saat write (alur di atas), TTL tetap dipasang sebagai jaring pengaman kalau DEL gagal.
- Nama/key berversi. Untuk aset di CDN, CloudFront merekomendasikan versioned file names (mis.
app.3f9a.css) untuk file yang sering diperbarui: mengalahkan salinan lama di browser dan proxy perusahaan, memudahkan rollback, dan lebih murah karena invalidation CDN berbayar. [6] - Push invalidation. Server mengirim pesan "key ini berubah" ke semua pemegang salinan. Contoh: Redis client-side caching (tracking) mengirim pesan
INVALIDATEke client yang pernah membaca key itu, dan client wajib menghapus salinan lokalnya. [7] Di HTTP, cache wajib meng-invalidate URI target setelah requestPUT/POST/DELETEyang berhasil lewat cache itu. [3]
Ingat lapisannya: menghapus key di Redis tidak menghapus salinan di CDN atau browser. Setiap lapisan dari lesson 0013 butuh cara invalidation sendiri.
Latihan 2 — Invalidation
Jawab tanpa scroll ke atas. Soal yang sama akan muncul lagi, diacak, di review 0019.
4. Kapan tidak perlu
Sinyal: mekanisme invalidation eksplisit (hapus saat write, apalagi push ke banyak instance) baru dibenarkan kalau requirement menyebut toleransi staleness yang lebih pendek dari TTL yang masuk akal, mis. "harga harus benar dalam 1 detik" sementara TTL 1 detik membuat hit ratio jatuh. Mengganti eviction policy dari default baru masuk akal kalau hit ratio yang diukur rendah.
Biaya dan risiko: setiap jalur write harus ingat menghapus key (satu jalur yang lupa = stale data diam-diam); push invalidation menambah koneksi dan memori di server (Redis tracking menyimpan tabel key per client) [7]; invalidation CDN dikenai biaya. [6]
Alternatif lebih murah: TTL pendek saja untuk data yang boleh basi beberapa detik atau menit; nama file berversi untuk aset statis;
allkeys-lru sebagai default eviction [5];
dan untuk data yang tidak boleh basi sama sekali (saldo, stok saat checkout), jangan di-cache: baca dari sumber utama. [4]
Latihan lisan — Ucapkan dengan suara keras
Pasang timer dan jawab dengan suara keras, seolah sedang interview. Jangan buka jawaban contoh sebelum selesai.
"Admin mengubah harga produk, tapi halaman produk masih menampilkan harga lama selama beberapa menit. Jelaskan penyebabnya dan cara Anda memperbaikinya tanpa over-engineering." (60 detik)
Bandingkan dengan jawaban contoh dan checklist-nya
"Penyebabnya stale data: cache masih memegang nilai lama sampai TTL habis, karena write tidak menghapus key. Pertama saya tanya requirement: harga boleh basi berapa lama? Kalau beberapa detik saja, perbaikan termurah adalah invalidation saat write: update database dulu, lalu hapus key; TTL tetap dipasang sebagai jaring pengaman kalau delete gagal. Saya cek juga lapisan lain: kalau halaman di-cache CDN atau browser, saya pakai URL berversi atau invalidation CDN. Push invalidation ke local cache di setiap instance, lewat pub/sub atau Redis tracking, baru saya tambahkan kalau angka menuntut, misalnya puluhan instance dengan local cache dan staleness harus di bawah TTL."
Checklist: apakah Anda menyebut…
- penyebab: cache memegang nilai lama sampai TTL habis (stale data)?
- invalidation saat write: update database dulu, lalu hapus key?
- TTL sebagai jaring pengaman bila delete gagal?
- lapisan lain (CDN/browser): URL berversi atau invalidation CDN?
- toleransi staleness dari requirement sebelum memilih mekanisme?
- push invalidation (pub/sub, tracking) dibenarkan dengan angka, bukan sebagai default?
Lulus jika minimal 4 dari 6.
maxmemory-policy dan cara kerja LRU/LFU aproksimasi.
Berikutnya, lesson 0015: apa yang terjadi saat key yang sangat populer kedaluwarsa (cache stampede), hot key, dan cache berlapis.
Istilah: GLOSSARY.md (bagian "Caching") · Indeks: semua lesson System Design
Ada yang belum jelas? Tanyakan ke saya (agent) di terminal, misalnya: "Kapan LFU lebih baik dari LRU?", "Berapa TTL yang wajar untuk profil user?"
Sumber: [1] Redis docs: EXPIRE · [2] Amazon ElastiCache: Caching strategies · [3] RFC 9111: HTTP Caching · [4] Azure Architecture Center: Cache-Aside pattern · [5] Redis docs: Key eviction · [6] Amazon CloudFront: Invalidate files to remove content · [7] Redis docs: Client-side caching reference