2 puan yazan flyingsquirrel 2026-04-17 | 4 yorum | WhatsApp'ta paylaş

layercache nedir?

Node.js'te Memory → Redis → Disk katmanlarını tek bir API altında birleştiren çok katmanlı bir önbellek kütüphanesidir.

Önbellek isabetinde değer en hızlı katmandan alınır ve üst katmanlar otomatik olarak doldurulur. Iska durumunda ise eşzamanlı 100 istek gelse bile fetcher yalnızca bir kez çalışır.

Neden yapıldı?

Node.js servisleri işletirken önbellek katmanlarını kurma biçimi genelde benzer bir süreç izler. In-memory önbellekle başlanır, instance sayısı artınca Redis eklenir, sonra stampede sorunuyla karşılaşılır, instance'lar arasında önbellek tutarsızlığı oluşur... Bunların her biri çözülebilecek sorunlar, ancak bunları production seviyesinde tek seferde bir araya getirmek düşünüldüğünden daha fazla emek gerektiriyordu.

Bu yüzden bu işi bir kez düzgün yapalım düşüncesiyle geliştirildi.

Temel özellikler neler?

Çekirdek davranış

  • Katmanlı okuma + otomatik backfill (L1 ıskası → L2 sorgusu → L1 doldurma)
  • Stampede prevention: eşzamanlı 100 istek → fetcher 1 kez çalışır
  • Distributed single-flight: Redis dağıtık kilidi ile instance'lar arası yinelenen çalıştırmaların kaldırılması
  • Redis pub/sub tabanlı L1 invalidation bus (instance'lar arasında bellek önbelleği senkronizasyonu)

Geçersiz kılma / tazelik

  • Etiket tabanlı geçersiz kılma, wildcard/önek geçersiz kılma
  • Stale-while-revalidate, Stale-if-error
  • Sliding TTL, Adaptive TTL, Refresh-ahead

Dayanıklılık

  • Graceful degradation: Redis arızasında katmanı atlayıp otomatik toparlanma
  • Circuit breaker
  • Strict / best-effort yazma politikası

Gözlemlenebilirlik

  • Prometheus exporter, OpenTelemetry hook'ları
  • Katman bazlı gecikme ölçümü, event hook'ları
  • Admin CLI (npx layercache stats|keys|invalidate)

Framework entegrasyonu
Express, Fastify, Hono, tRPC, GraphQL, Next.js

Benchmark sayıları nasıl?

Tek çekirdekli VM + gerçek Docker Redis baz alınmıştır.

| Senaryo | Ortalama gecikme |
| L1 bellek sıcak isabeti | 0.005 ms |
| L2 Redis sıcak isabeti (1 KiB) | 0.193 ms |
| Önbellek yok (DB simülasyonu) | 5.030 ms |

  • HTTP throughput: /layered 16,211 req/s vs /nocache 158 req/s
  • Stampede: eşzamanlı 75 istek → origin fetch 5 kez (önbellek olmadan 375 kez)
  • Distributed single-flight: eşzamanlı 60 istek → origin fetch 1 kez

Tüm benchmark metodolojisi ve ham sonuçlar docs/benchmarking.md içinde derlenmiştir.

Mevcut kütüphanelerden farkı ne?

node-cache-manager, keyv, cacheable iyi seçeneklerdir. Farkları kısaca özetlemek gerekirse:

  • Stampede prevention / Distributed single-flight: Bu üç kütüphanenin hiçbiri bunları varsayılan olarak sunmaz. layercache bu iki özelliği merkeze alacak şekilde tasarlanmıştır.
  • Cross-instance L1 invalidation: Redis pub/sub ile instance'lar arasındaki bellek önbelleği otomatik olarak senkronize edilir. Çoklu instance ortamlarında bellek önbelleği güvenle kullanılabilir.
  • Auto backfill: Alt katmanda isabet olduğunda üst katmanlar otomatik olarak doldurulur.
  • Graceful degradation + Circuit breaker: Redis çökse bile servis ayakta kalır.

Kurulum ve bağlantılar

npm install layercache  

Tasarım kararları, özellikle single-flight koordinasyon yöntemi veya graceful degradation davranışı hakkında merak ettikleriniz varsa rahatça sorabilirsiniz.

4 yorum

 
sugeuljin 2026-04-18

Güzel bir kütüphane!
Redis'in tasarıma dahil edilmesinin özel bir nedeni var mı? Aynı anda birden fazla salt okunur instance'ın ayağa kalktığı bir senaryo mu varsayılıyor? Eğer öyleyse, (yerel) Disk katmanının Redis'ten daha ön katmanda konumlandırılması gerekmez mi?

 
flyingsquirrel 2026-04-18

Redis’in dahil edilmesinin nedeni, birden fazla sunucu olduğu durumu varsaymak. Her sunucunun belleği farklı değerlere sahip olabilir; bu yüzden Redis "paylaşılan gerçek" rolünü üstlenir.

Disk’in Redis’ten sonra gelmesinin nedeni, Redis’in aynı yerel ağda olduğu varsayımı altında daha hızlı olması. Benchmark’a göre Disk ~2ms, Redis ise ~0.02ms. Ancak Redis uzaktaysa ya da ağ kötüyse yerel Disk daha hızlı olabilir; böyle durumlarda sıralamayı değiştirmek doğru olur. Kütüphane de sıralamayı zorunlu kılmıyor, yapıyı kullanıcı doğrudan belirliyor.

Disk’in nerede olduğundan bağımsız olarak, asıl amacı hız yarışı değil; Memory ve Redis tamamen çöktüğünde ayakta kalan son sigorta görevi görmek.

 
sugeuljin 2026-04-18

Tasarım niyetini paylaştığınız için teşekkürler.
Tüm uzak çağrıları yerel disk yazımı olarak saklayıp, uzak çağrı başarısız olduğunda diskten okuma yapıldığını kastediyorsunuz, değil mi? Cache katmanında Disk’in gerçekten gerekli olup olmadığını da değerlendirmeniz iyi olabilir.

 
flyingsquirrel 2026-04-18

DiskLayer o tür bir desen değil; yalnızca normal bir cache katmanı gibi çalışıyor — hem okuma hem yazma yapıyor ve üst katmanda miss olursa sırayla erişen bir yapısı var. Kafa karışıklığına neden olduysam kusura bakmayın.
Bahsettiğiniz "uzak çağrı sonucunu diske kaydedip hata durumunda oradan okuma" deseni aslında stale-if-error seçeneğine daha yakın, ama o bellekte tutulduğu için süreç yeniden başlatılırsa kayboluyor.
Ayrıca DiskLayer'ın gerçekten gerekli olup olmadığına dair eleştiri için, şey. Pratikte çoğu çoklu instance ortamında Memory → Redis tek başına yeterli oluyor; Disk katman olarak devreye girdiği anda da serileştirme maliyeti ve dosya yönetimi karmaşıklığı beraberinde geliyor.