Strategi Caching: Cache-Aside, Write-Through, dan Write-Back

Perbandingan strategi caching (cache-aside, read-through, write-through, write-around, write-back), kelebihan, risiko, dan kapan memakai masing-masing.

Strategi caching menentukan kapan data masuk ke cache dan kapan ditulis ke database. Ada lima pola utama. Cache-aside mengisi cache hanya saat data diminta dan tidak ditemukan. Read-through mendelegasikan pengisian itu ke lapisan cache. Write-through menulis ke cache dan database sekaligus. Write-around menulis langsung ke database dan melewati cache. Write-back menulis ke cache dulu, lalu ke database belakangan. Pilihan terbaik bergantung pada rasio baca/tulis dan seberapa besar toleransi Anda terhadap data basi atau data hilang.

Tiga strategi caching yang paling sering dipakai, dan arah aliran datanya.

Kenapa caching dibutuhkan

Membaca dari memori (misalnya Redis atau Memcached) biasanya selesai dalam hitungan mikrodetik sampai sekitar satu milidetik. Query ke database relasional yang menyentuh disk dan melewati jaringan bisa memakan puluhan milidetik atau lebih. Pada sistem dengan pola baca yang dominan (misalnya halaman produk, profil pengguna, atau konfigurasi), cache menurunkan latensi dan mengurangi beban database sekaligus.

Tapi cache adalah salinan data. Begitu ada salinan, muncul pertanyaan klasik: bagaimana menjaga keduanya tetap sinkron? Setiap strategi di bawah ini menjawab pertanyaan itu dengan trade-off yang berbeda.

Strategi untuk membaca data

Cache-aside (lazy loading)

Aplikasi bertanggung jawab penuh atas cache:

  1. Cari data di cache.
  2. Jika miss, baca dari database.
  3. Simpan hasilnya ke cache dengan TTL, lalu kembalikan ke pemanggil.
async function getUser(id: string) {
  const cached = await redis.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  const user = await db.users.findById(id);
  if (user) {
    await redis.set(`user:${id}`, JSON.stringify(user), { EX: 300 }); // TTL 5 menit
  }
  return user;
}

Kelebihan: hanya data yang benar-benar diminta yang masuk cache, dan jika cache mati, aplikasi tetap bisa berjalan (hanya lebih lambat). Kekurangan: permintaan pertama selalu miss, dan data di cache bisa basi sampai TTL habis atau key dihapus.

Ini pola paling umum dan titik awal yang aman untuk kebanyakan aplikasi.

Read-through

Mirip cache-aside, tetapi logika “miss → baca database → isi cache” dipindahkan ke lapisan cache atau library, bukan di kode aplikasi. Aplikasi cukup memanggil cache.get(key). Hasilnya kode lebih bersih, tapi Anda bergantung pada library/penyedia cache yang mendukung pola ini.

Strategi untuk menulis data

Write-through

Setiap penulisan masuk ke cache dan database secara sinkron, dan baru dianggap sukses setelah keduanya berhasil. Cache selalu berisi data terbaru, sehingga pembacaan berikutnya hampir pasti hit.

Harganya: latensi tulis bertambah (dua penulisan per operasi), dan cache bisa terisi data yang jarang dibaca.

Write-around

Penulisan langsung ke database dan melewati cache. Key yang terkait biasanya dihapus (invalidate) agar pembacaan berikutnya mengambil data segar. Cocok untuk data yang ditulis sekali dan jarang dibaca ulang, seperti log atau arsip.

Write-back (write-behind)

Aplikasi hanya menulis ke cache, lalu cache menyalin ke database secara asinkron, sering dalam batch. Latensi tulis sangat rendah dan database terlindung dari lonjakan tulis.

Perbandingan singkat

Strategi Latensi baca Latensi tulis Konsistensi Risiko utama Cocok untuk
Cache-aside Miss pertama lambat Normal Bisa basi s.d. TTL Data basi Beban baca umum
Read-through Miss pertama lambat Normal Bisa basi s.d. TTL Ketergantungan library Beban baca, kode lebih rapi
Write-through Cepat (sering hit) Lebih tinggi Kuat Cache penuh data jarang dibaca Data yang ditulis lalu dibaca
Write-around Miss setelah tulis Normal Kuat (setelah miss) Miss setelah setiap update Data jarang dibaca ulang
Write-back Cepat Sangat rendah Eventual Kehilangan data Beban tulis sangat tinggi

Dalam praktik, kombinasi yang paling sering dipakai adalah cache-aside untuk baca + invalidasi (hapus key) saat tulis.

Masalah yang sering muncul

Cache stampede (thundering herd)

Saat key populer kedaluwarsa, ribuan request bisa miss bersamaan dan menghantam database di waktu yang sama. Beberapa mitigasinya:

  • Lock/single-flight: hanya satu request yang mengisi ulang cache, sementara yang lain menunggu.
  • TTL dengan jitter: tambahkan variasi acak pada TTL supaya key tidak kedaluwarsa serentak.
  • Refresh lebih awal: perbarui key di background sebelum TTL benar-benar habis.

Update vs hapus saat invalidasi

Saat data berubah, menghapus key umumnya lebih aman daripada menimpa nilainya. Dengan dua penulisan paralel, operasi “update cache” bisa tiba dengan urutan terbalik dan meninggalkan nilai lama di cache. Menghapus key memaksa pembacaan berikutnya mengambil data terbaru dari database.

Kebijakan eviction

Memori cache terbatas. Saat penuh, cache membuang key berdasarkan kebijakan seperti LRU (paling lama tidak diakses) atau LFU (paling jarang diakses). Redis, misalnya, mengaturnya lewat opsi maxmemory-policy.

Cara memilih

  • Mayoritas beban adalah baca dan data boleh sedikit basi → cache-aside dengan TTL.
  • Data harus langsung konsisten setelah ditulis dan sering dibaca → write-through.
  • Data ditulis sekali dan jarang dibaca → write-around.
  • Tulis sangat intens dan kehilangan sebagian data bisa diterima → write-back.

Mulailah dari yang paling sederhana (cache-aside), ukur hit ratio dan latensi, lalu naikkan kompleksitas hanya jika angka menunjukkan perlu.

  • #caching
  • #redis
  • #performa
  • #system-design