2 poin oleh flyingsquirrel 2026-04-17 | 4 komentar | Bagikan ke WhatsApp

Apa itu layercache?

Ini adalah pustaka cache multilapis yang menyatukan Memory → Redis → Disk dalam satu API di Node.js.

Saat cache hit terjadi, nilai diambil dari layer tercepat dan layer yang lebih atas diisi otomatis. Saat miss terjadi, bahkan jika ada 100 permintaan bersamaan, fetcher hanya akan dijalankan tepat satu kali.

Mengapa dibuat?

Saat mengoperasikan layanan Node.js, cara menumpuk layer caching umumnya mengikuti pola yang mirip. Dimulai dari cache in-memory, lalu ketika jumlah instance bertambah ditambahkan Redis, kemudian muncul masalah stampede, lalu terjadi ketidaksesuaian cache antar-instance... Masing-masing masalah sebenarnya bisa diselesaikan, tetapi merangkainya sekaligus ke tingkat production ternyata membutuhkan usaha yang lebih besar dari perkiraan.

Karena itu, pustaka ini dibuat dengan gagasan untuk menyelesaikan pekerjaan tersebut sekali dengan benar.

Apa saja fitur utamanya?

Perilaku inti

  • Pembacaan berlapis + backfill otomatis (L1 miss → cek L2 → isi L1)
  • Pencegahan stampede: 100 permintaan bersamaan → fetcher dieksekusi 1 kali
  • Distributed single-flight: menghilangkan eksekusi duplikat antar-instance dengan Redis distributed lock
  • L1 invalidation bus berbasis Redis pub/sub (sinkronisasi cache memori antar-instance)

Invalidasi / kesegaran

  • Invalidasi berbasis tag, invalidasi wildcard/prefiks
  • Stale-while-revalidate, Stale-if-error
  • Sliding TTL, Adaptive TTL, Refresh-ahead

Ketahanan

  • Graceful degradation: saat Redis mengalami gangguan, layer dilewati lalu pulih otomatis
  • Circuit breaker
  • Kebijakan penulisan strict / best-effort

Observabilitas

  • Prometheus exporter, hook OpenTelemetry
  • Pengukuran latensi per layer, hook event
  • Admin CLI (npx layercache stats|keys|invalidate)

Integrasi framework
Express, Fastify, Hono, tRPC, GraphQL, Next.js

Ingin tahu angka benchmark-nya

Berdasarkan single-core VM + Docker Redis nyata.

| Skenario | Latensi rata-rata |
| L1 memory warm hit | 0.005 ms |
| L2 Redis warm hit (1 KiB) | 0.193 ms |
| Tanpa cache (simulasi DB) | 5.030 ms |

  • Throughput HTTP: /layered 16,211 req/s vs /nocache 158 req/s
  • Stampede: 75 permintaan bersamaan → origin fetch 5 kali (tanpa cache menjadi 375 kali)
  • Distributed single-flight: 60 permintaan bersamaan → origin fetch 1 kali

Metodologi benchmark lengkap dan hasil raw telah dirangkum di docs/benchmarking.md.

Apa bedanya dengan pustaka yang sudah ada?

node-cache-manager, keyv, dan cacheable semuanya merupakan pilihan yang baik. Jika diringkas singkat, perbedaannya adalah:

  • Stampede prevention / Distributed single-flight: ketiga pustaka tersebut tidak menyediakannya secara bawaan. layercache dirancang dengan dua hal ini sebagai inti.
  • Cross-instance L1 invalidation: secara otomatis menyinkronkan cache memori antar-instance melalui Redis pub/sub. Cache memori dapat digunakan dengan lebih tenang di lingkungan multi-instance.
  • Auto backfill: saat hit terjadi di layer bawah, layer atas akan diisi otomatis.
  • Graceful degradation + Circuit breaker: layanan tetap hidup meskipun Redis mati.

Instalasi dan tautan

npm install layercache  

Jika Anda penasaran dengan keputusan desain, khususnya cara koordinasi single-flight atau perilaku graceful degradation, silakan bertanya dengan santai.

4 komentar

 
sugeuljin 2026-04-18

Library yang bagus!
Apakah ada alasan Redis dimasukkan dalam desain? Apakah ini untuk skenario yang mengasumsikan beberapa instance khusus-baca berjalan secara bersamaan? Kalau begitu, bukankah Disk (lokal) seharusnya ditempatkan di layer yang lebih depan daripada Redis?

 
flyingsquirrel 2026-04-18

Redis disertakan dengan asumsi servernya ada beberapa. Karena memori di tiap server bisa berisi nilai yang berbeda, Redis berperan sebagai "sumber kebenaran bersama".

Disk ditempatkan setelah Redis karena dengan asumsi Redis berada di jaringan lokal yang sama, Redis lebih cepat. Berdasarkan benchmark, Disk sekitar ~2ms, sedangkan Redis sekitar ~0.02ms. Namun jika Redis berada jauh atau jaringannya buruk, Disk lokal bisa lebih cepat, dan dalam kasus seperti itu memang tepat untuk menukar urutannya. Library ini juga tidak memaksakan urutan dan dirancang agar pengguna bisa menentukannya sendiri.

Apa pun lokasinya, tujuan utama Disk bukan untuk bersaing soal kecepatan, melainkan sebagai perlindungan terakhir yang tetap bertahan saat Memory dan Redis sama-sama mati.

 
sugeuljin 2026-04-18

Terima kasih atas niat desainnya. Hehe
Maksud Anda, semua pemanggilan jarak jauh disimpan sebagai penulisan ke disk lokal, lalu saat pemanggilan jarak jauh gagal, pembacaan dilakukan dari disk, benar begitu? Mungkin ada baiknya juga mempertimbangkan apakah layer cache memang benar-benar perlu memiliki Disk.

 
flyingsquirrel 2026-04-18

DiskLayer tidak memakai pola seperti itu, melainkan berfungsi sebagai layer cache biasa — bisa membaca dan menulis, dengan struktur yang mengakses layer berikutnya secara berurutan jika terjadi miss di layer atas. Maaf kalau sempat membingungkan.
Pola yang Anda sebutkan, yaitu "menyimpan hasil panggilan jarak jauh ke disk lalu membacanya saat gagal", sebenarnya lebih dekat ke opsi stale-if-error, tetapi itu disimpan di memori, jadi akan hilang ketika proses di-restart.
Dan soal apakah DiskLayer benar-benar diperlukan, ya. Dalam praktiknya, di sebagian besar lingkungan multi-instans, Memory → Redis saja sudah cukup, dan begitu Disk masuk sebagai layer, akan muncul biaya serialisasi serta kerumitan pengelolaan file.