Spring Cache — @Cacheable Kimin Cevabını Hatırlıyor?
Önce şunu oku: AOP, Proxy ve Self-Invocation Tuzağı , Transaction Propagation ve Rollback Yayılımı
30 saniyede özet
@Cacheable bir sonucu bir anahtarla saklar ve bir dahakine metodu hiç çalıştırmadan onu verir. Anahtar, sonucu değiştiren her şeyi içermeli; birden çok sunucu varsa her birinin defteri ayrıdır.
Fiyatları güncelledin ve iki şikâyet geldi. Biri sepette eski fiyatı görmüş, diğeri dolar fiyatı yerine lira fiyatı. İkisi de aynı @Cacheable satırından çıktı.
Adım adım oku
- Biri 7 numaralı ürünün fiyatını dolar olarak soruyor.
- Cache anahtarı yalnızca ürün numarasından oluşuyor; cevap deftere ürün 7 satırına yazılıyor.
- Lira olarak soran ikinci kişi de aynı satırı buluyor ve dolar fiyatını alıyor.
- Anahtar sonucu değiştiren her girdiyi içermeli: ürün ve para birimi birlikte. O zaman her soru kendi satırını bulur.
-
Bayt: Fiyatları güncelledim ve iki şikâyet geldi!
-
Sen: Ne şikâyeti?
-
Bayt: Biri eski fiyatı görmüş, öteki dolar yerine lira. İkisi de aynı @Cacheable satırından!
-
Bayt: Garsonun defterine ne yazıldığına bakalım: sorunun tamamı mı, yarısı mı?
Cache aslında bir defter
@EnableCaching açıkken Spring, @Cacheable metodunun önüne bir aracı (proxy) koyar. Aracı gelen soruya bir anahtar (key) verir ve deftere bakar: cevap yazılıysa metodu hiç çağırmaz, yazılı değilse çağırır ve cevabı deftere yazar.
Varsayılan anahtar metodun bütün parametreleridir. key = "#productId" yazdığın an bu güvence gider: anahtarda olmayan her parametre, farklı sorulara aynı cevabın dönmesine yol açar (dolar fiyatı sorana lira fiyatı gibi).
Aracı yalnızca dışarıdan gelen çağrıları gördüğü için this.find(id) gibi iç çağrılar deftere hiç uğramaz.
Hiç ayar yapmazsan· istersen atla
Projede Caffeine ya da Redis yoksa Boot, süresi ve boyut sınırı olmayan basit bir ConcurrentHashMap kurar. Deneme için yeter, canlı sistemde bellek dolana kadar büyür.
Kafam karıştı, daha basit anlat
Cache bir not defteridir: aynı soru gelince cevabı yeniden hesaplamaz, deftere bakar. Sorunun bir kısmını not almayı unutursan, farklı sorulara aynı cevabı verir.
Spring Boot uygulamasında @EnableCaching açtın, ama classpath'te Caffeine ya da Redis yok. @Cacheable değerleri nerede ve ne kadar süre tutulur?
@Cacheable(value = "prices", key = "#productId") ile işaretli getPrice(long productId, String currency) metodu var. Ne olur?
Defter nasıl güncellenir?
İki yol var. TTLTime to live: bir cache girdisinin ne kadar süre geçerli sayılacağı. Süre dolunca girdi silinir ve sonraki okuma kaynağa gider; o süre boyunca eski veri görülebilir.Sözlükte gör → girdiyi belirli bir süre sonra kendiliğinden siler; o süre boyunca eski veri görülebilir. @CacheEvict ise güncelleme anında girdiyi siler, sonraki okuma veritabanına gider.
İki pod, her birinde yerel Caffeine cache. Fiyat güncellemesi @CacheEvict taşıyor ve istek Pod A'ya düştü. Pod B ne gösterir? Cevabı göster
Eski fiyatı, TTL dolana kadar. Yerel cache her JVM’de ayrı bir kopyadır. Evict yalnızca çağrının düştüğü pod’un kopyasını siler; Spring diğer pod’lara haber vermez.
Kafam karıştı, daha basit anlat
Her sunucunun kendi defteri var. Birinin defterinden bir satırı silmek, ötekilerin defterini değiştirmez. Onlar eski cevabı süre dolana kadar vermeye devam eder.
Üç pod, her birinde Caffeine ile yerel cache. Fiyat güncelleme uç noktası @CacheEvict taşıyor ve istek Pod 1'e düştü. Kullanıcılar ne görür?
@CacheEvict ile @CachePut arasındaki fark nedir?
Kendin gör
Cache kimin fiyatını hatırlıyor?
Tohum 548711Pod A cache
boş
Pod B cache
boş
Oynat ya da adımla.
Şu an ne oldu?
Her pod kendi cache'i (Caffeine)
İki pod aynı fiyatı okuyor, sonra yönetici fiyatı değiştiriyor. Cache değişikliği duyacak mı?
Görevler0/3
Dolar isteyene lira fiyatı döndüraçık
İpucu
Key'den bir parametre eksik olsun.
Evict çalışsın, ama bir pod yine eski fiyatı görsünaçık
İpucu
Cache nerede duruyor?
Her okuma doğru fiyatı görsünaçık
İpucu
Doğru key, ortak cache, güncellemede evict.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Evict yok: güncellemeden sonra iki pod da eski fiyatta.
- “@CacheEvict” seç. Pod A düzeldi, Pod B hâlâ eski.
- Cache’i “Ortak cache (Redis)” yap. İki pod da yeni fiyatı görüyor.
- Key’i
#productIdyap. Dolar isteyen lira fiyatı aldı.
Ürün sayfası her istekte veritabanına gidiyor; cache hiç dolmuyor gibi. @EnableCaching açık. Hatalı satır hangisi?
Her veriyi en uygun cache yaklaşımına göre ayır.
Tuzaklar
Kayıttan önce silmek. @Transactional metottaki evict, değişiklik veritabanına kaydedilmeden önce çalışır. Arada gelen bir okuma eski değeri yeniden deftere yazar; cache manager’ı transaction-aware yaparak silmeyi kayıttan sonraya al.
Değiştirilebilir değerler. Yerel cache nesnenin kendisini döndürür. Dönen nesneyi değiştiren kod, cache’i de değiştirir; cache’lenen tipleri record yap.
cache stampedeSık okunan bir cache girdisi silindiği anda çok sayıda isteğin aynı değeri aynı anda kaynaktan hesaplamaya çalışması. Veritabanına ani bir yük bindirir.Sözlükte gör → (izdiham). Çok sorulan bir cevap defterden silindiği anda yüzlerce istek aynı sorguyu aynı anda çalıştırır. @Cacheable(sync = true) bunu tek bir sunucu içinde tek sorguya indirir.
Karar anında cache. Ödeme anındaki stok ya da bakiye kontrolü cache’ten okunmaz. Cache’i, biraz eskimesi zarar vermeyen okumalara sakla.
Popüler bir ürünün cache girdisinin TTL'i doldu ve aynı anda 500 istek geldi. Veritabanı CPU'su sıçradı. Bu neyin belirtisi ve Spring'de ilk yardım nedir?
Aşağıdaki örnek bir bankanın döviz kuru servisinden ve dersteki kararları birlikte uyguluyor: ortak cache, sonucu değiştiren her parametreyi içeren key, commit’ten sonra evict, stampede koruması ve değiştirilemez değerler.
Derinleş · Beş pod'lu döviz kuru servisi: uçtan uca 6 dosya · ~118 satır · ilk okumada atlayabilirsin
Kendini sına
@Cacheable, cevap defterde varsa metodu hiç çalıştırmaz.
@Transactional updatePrice metodu @CacheEvict taşıyor. Nadiren, güncellemeden sonra cache'te yine eski fiyat kalıyor ve TTL dolana kadar düzelmiyor. Neden?
Aklında kalacak üç şey
- 1 Cache anahtarı, metodun sonucunu değiştiren her şeyi içermelidir. Varsayılan anahtar bütün parametreleri kullanır; elle yazılan anahtar bu güvenceyi kaldırır.
- 2 Yerel cache her sunucuda ayrı bir kopyadır. @CacheEvict yalnızca çağrının düştüğü sunucunun kopyasını siler.
- 3 TTL, verinin en fazla ne kadar eski olabileceğini söyler. Değişikliğin hemen görünmesi gerekiyorsa evict gerekir ve evict commit'ten sonra çalışmalıdır.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.
- System Design & Dağıtık SistemlerCache Stratejileri — Defter Ne Zaman Yalan Söyler?Fiyatı değiştirdin, cache'i de güncelledin. Ekran neden hâlâ eski fiyatı gösteriyor?Derse git
- Hibernate ve JPAİkinci Seviye Cache — Hangi Cache, Hangi Soruya Cevap Verir?Bir güncellemeden sonra bazı sunucular hâlâ eski fiyatı gösteriyor. Veri nerede saklanıyordu?Derse git