Lompat ke konten
20 menit bacamateri 33 dari 96

Pilih kebijakan penulisan

Cache-aside, write-through, dan invalidasi punya race yang berbeda. Telusuri urutan operasinya sebelum memilih.

Ditinjau 26 Oktober 2026

Pertanyaan

Saat data berubah, kapan dan oleh siapa cache diperbarui, dan urutan mana yang bisa meninggalkan nilai lama selamanya?

Setelah baca ini, kamu bisa menggambar garis waktu dua operasi konkuren dan menunjukkan apakah sebuah kebijakan penulisan bisa meninggalkan nilai usang.

Prasyarat dan contoh

Kamu sudah punya key yang benar (M06.02) dan paham transaksi serta isolasi dasar di basis data (M05). Satu hal penting: basis data adalah sumber kebenaran, cache hanyalah salinan.

Contoh: profil toko dengan field nama dan status_buka. Pemilik toko menekan "tutup" lalu pelanggan tetap melihat "buka" selama 10 menit. Bukan karena cache lambat, tapi karena urutan operasi yang mengisi cache dengan nilai lama setelah invalidasi terjadi.

Mekanisme

Cache-aside (lazy loading). Aplikasi yang mengelola cache.

baca:  v = cache.get(k); jika kosong: v = db.read(k); cache.set(k, v, ttl)
tulis: db.write(k, baru); cache.delete(k)

Sederhana, dan cache hanya berisi data yang pernah diminta. Kelemahannya ada pada baca setelah miss: ada jeda antara membaca DB dan menulis cache.

Write-through. Setiap tulis lewat lapisan cache, yang menulis ke DB dan cache bersama-sama.

tulis: db.write(k, baru); cache.set(k, baru)

Cache hampir selalu hangat, tapi dua penulisan tetap bukan satu operasi atomik. Kalau tulis ke cache gagal setelah DB sukses, cache menyimpan nilai lama. Dan data yang tidak pernah dibaca ikut menempati memori.

Invalidasi. Hapus atau tandai usang entri saat sumber berubah. Biasanya dipakai bersama cache-aside. Invalidasi lebih aman daripada set karena nilai yang dihapus tidak bisa salah.

Race yang harus dikenali. Garis waktu cache-aside dengan dua klien:

t1  Pembaca A: cache miss, baca DB -> status_buka = true
t2  Penulis B: tulis DB status_buka = false
t3  Penulis B: cache.delete(k)
t4  Pembaca A: cache.set(k, true)     <- nilai usang masuk setelah delete

Setelah t4 cache berisi true sampai TTL habis, padahal DB berisi false. Tidak ada error dan tidak ada log. Kemungkinannya kecil per operasi, tapi di 1.000 baca per detik pada key populer hampir pasti terjadi.

Pilihan pengendalian, dari yang paling murah:

  1. TTL sebagai batas atas. Kesalahan paling lama sama dengan TTL. Ini pagar pengaman minimum, bukan solusi.
  2. Versi pada nilai. Simpan versi baris bersama nilai. set hanya menimpa kalau versi baru lebih besar (bisa dengan skrip atomik di Redis). Pembaca A di t4 membawa versi lama sehingga ditolak.
  3. Hapus ganda tertunda. Hapus saat tulis, lalu hapus lagi beberapa ratus ms kemudian untuk menyapu nilai yang masuk terlambat. Ini heuristik: waktu tunda harus lebih besar dari durasi baca terpanjang, dan itu tidak dijamin.
  4. Jangan pakai cache untuk data yang butuh kebenaran mutlak. Saldo dan stok akhir saat checkout dibaca langsung dari DB.

Saat rancangan ini gagal

  • set setelah tulis menimpa nilai yang lebih baru. Dua penulis konkuren menulis DB berurutan A lalu B, tapi set cache berurutan B lalu A. Cache berisi A, DB berisi B. Itu alasan menghapus lebih aman daripada mengisi pada jalur tulis.
  • Invalidasi hilang. Aplikasi crash antara db.write dan cache.delete. Cache tetap lama sampai TTL. Kalau TTL tidak ada, ia lama selamanya.
  • Invalidasi tidak mencakup semua key turunan. Satu perubahan harga muncul di key detail, daftar, dan pencarian. Menghapus satu key saja meninggalkan dua lainnya.
  • Replika baca tertinggal. Setelah invalidasi, pembaca melewatkan cache dan membaca replika yang belum menerima tulisan, lalu menyimpan nilai lama kembali. Baca dari primary saat mengisi ulang setelah tulis, atau tahan pengisian untuk key yang baru diubah.
  • Write-through dengan satu penulis yang gagal separuh. DB sukses, cache gagal, dan klien menerima error lalu retry. Retry harus idempoten (M03), kalau tidak efeknya berlipat.

Contoh tandingan: tim memilih write-through "agar selalu sinkron" dan menulis cache lebih dulu sebelum DB. Transaksi DB gagal rollback, tapi cache sudah berisi nilai yang tidak pernah benar-benar tersimpan. Pembaca melihat data yang tidak ada di sumber kebenaran.

Latihan

Tabel stok_hadiah dibaca 800 kali per detik dan ditulis kira-kira sekali per menit. Aplikasi memakai cache-aside, TTL 10 menit, dan pada tulis melakukan db.write lalu cache.delete.

  1. Gambar garis waktu yang membuat cache menyimpan stok lama.
  2. Berapa lama paling buruk nilai itu bertahan?
  3. Sebut dua perubahan yang menyempitkan masalahnya.
Lihat pembahasan

Garis waktu: pembaca A miss dan membaca DB (stok 10) pada t1. Penulis B menulis stok 9 dan menghapus cache pada t2 dan t3. Pembaca A baru menulis cache pada t4 dengan nilai 10. Kini cache berisi 10 dan DB berisi 9.

Paling buruk nilai itu bertahan selama TTL: 10 menit. Dengan 800 baca per detik, jendela t1 ke t4 (misalnya 5 ms) kena oleh kira-kira 4 pembaca yang miss bersamaan, jadi ini terjadi di praktik, bukan hanya di teori.

Perubahan yang membantu: (1) simpan nomor versi baris bersama nilai dan hanya terima set dengan versi lebih tinggi, (2) pendekkan TTL menjadi 60 detik supaya kesalahan terburuk sama dengan toleransi bisnis. Untuk stok saat checkout, tetap baca langsung dari DB.

Terkait

Catatan

  • Asumsi: satu DB primer sebagai sumber kebenaran, cache dengan operasi get, set, delete yang tidak transaksional bersama DB.
  • Yang tidak dibahas: change data capture untuk invalidasi dan write-behind.
  • Angka jendela race adalah ilustrasi. Ukur durasi baca DB aslimu.
  • Terakhir ditinjau: 26 Oktober 2026.

Isi · System Design