Veri önbellekte bulunur ve asıl kaynağa hiç gidilmeden döner. Hit oranı (hit ratio) ne kadar yüksekse, önbellek o kadar iş yapıyordur.
Bir veriyi her seferinde yeniden hesaplamak ya da yavaş bir kaynaktan tekrar tekrar çekmek pahalıdır. Önbellekleme, sık istenen veriyi kullanıcıya daha yakın ve daha hızlı bir yerde tutarak bu maliyeti azaltır — ama sakladığınız her kopya, bir gün eskiyecek bir veridir. Bu sayfada önbelleğin nerede durduğunu, hangi desenle yazılıp okunduğunu, ne zaman geçersiz kılındığını ve Redis'in bu işin neresinde olduğunu birlikte ve adım adım yan yana koyduk.
Önbellek (cache), pahalı bir işlemin sonucunu hızlı erişilebilir bir yerde tutup bir sonraki istekte yeniden hesaplamadan veren bir ara katmandır. İstenen veri önbellekte bulunursa bu bir cache hit'tir ve yanıt hızlıdır; bulunmazsa cache miss olur, veri asıl kaynaktan çekilir ve genellikle bir sonraki sefer için önbelleğe yazılır. Önbelleklemenin değeri iki gözleme dayanır: aynı veri sık sık istenir (temporal locality) ve yavaş kaynağa erişim, bellekten okumaya göre kat kat pahalıdır.
# istek gelir → önce önbelleğe bak
val = cache.get("user:42")
HIT val varsa → doğrudan döndür # hızlı yol
MISS val yoksa → DB'den çek
cache.set("user:42", row, ttl=300)
row'u döndür # yavaş yol, bir kez
Veri önbellekte bulunur ve asıl kaynağa hiç gidilmeden döner. Hit oranı (hit ratio) ne kadar yüksekse, önbellek o kadar iş yapıyordur.
Veri önbellekte yoktur; asıl kaynaktan çekilir, döndürülür ve çoğunlukla bir sonraki istek için önbelleğe yazılır. İlk istek hep miss'tir (cold cache).
Hit / (hit + miss). %95 hit oranı, isteklerin yalnızca yirmide birinin yavaş kaynağa gittiği anlamına gelir. Düşük oran, yanlış anahtar ya da çok kısa TTL işaretidir.
Önbellekleme tek bir yerde olmaz; bir isteğin yolu boyunca birçok katmanda tekrarlanır. Tarayıcı yanıtı diske alır, CDN içeriği kenarda tutar, uygulama sık sorguların sonucunu Redis gibi bir bellek deposunda saklar, veritabanı da sorgu planlarını ve sayfalarını kendi belleğinde önbellekler. Her katman bir öncekinin yükünü hafifletir; veri kullanıcıya ne kadar yakında bulunursa yanıt o kadar hızlıdır.
Browser yerel disk / bellek # 0 ağ turu
CDN kenar (edge) PoP # kullanıcıya yakın
App / Redis in-memory key-value # uygulama katmanı
DB cache buffer pool / plan # kaynağa en yakın
# istek üstten alta süzülür; üst katmanda
# bulunan veri alttakini hiç yormaz.
Cache-Control, ETag ve Last-Modified başlıkları, tarayıcının yanıtı ne kadar ve nasıl saklayacağını söyler. En ucuz önbellek, hiç ağ turu gerektirmeyenidir.
Statik varlıklar ve önbelleklenebilir yanıtlar, kullanıcıya en yakın PoP'ta tutulur; origin sunucu yorulmaz. Ayrıntı için CDN, DDoS & Edge başlığına bakabilirsiniz.
Sorgu sonuçları, render edilmiş parçalar ve oturumlar gibi dinamik veriler, Redis ya da Memcached gibi paylaşılan bir bellek deposunda tutulur. Bu sayfanın asıl odağı bu katmandır.
Önbelleğin nasıl doldurulup güncellendiği bir desen seçimidir ve veri tutarlılığını doğrudan belirler. Cache-aside'da yükü uygulama yönetir; read-through ve write-through'da bu sorumluluk önbellek katmanına devredilir; write-behind ise yazmayı geciktirerek hızlanır ama veri kaybı riskini kabul eder. Doğru desen, okuma/yazma oranınıza ve eskimiş veriye ne kadar tahammül edebildiğinize bağlıdır.
| Desen | Yükü kim yönetir | Yazma yolu | Uygun olduğu yer |
|---|---|---|---|
Cache-aside |
Uygulama | DB'ye yazıp anahtarı siler | Okuma ağırlıklı, en yaygın varsayılan |
Read-through |
Önbellek katmanı | Ayrı yazma deseni gerekir | Uygulamayı sadeleştirmek istendiğinde |
Write-through |
Önbellek katmanı | Önbellek + DB eşzamanlı | Tutarlılık önemliyse; yazma yavaşlar |
Write-behind |
Önbellek katmanı | Önce önbellek, sonra asenkron DB | Yazma yoğun; veri kaybı riski kabul edilirse |
Uygulama önce önbelleğe bakar, miss'te DB'den çekip yazar. Yazma sırasında ilgili anahtarı siler (invalidate), böylece bir sonraki okuma tazesini çeker.
Her yazma hem önbelleğe hem DB'ye gider. Önbellek hep güncel kalır ama yazma gecikmesi artar; az yazılan, çok okunan veride değerlidir.
Yazma önce önbelleğe alınır, DB'ye toplu ve asenkron işlenir. Çok hızlıdır ama önbellek çökerse henüz yazılmamış veri kaybolabilir.
Önbelleğin zor yanı veriyi saklamak değil, ne zaman atacağına karar vermektir. TTL bir kaydın kaç saniye sonra kendiliğinden geçersiz olacağını söyler; invalidation, veri değiştiğinde ilgili kaydı elle siler; eviction ise bellek dolduğunda hangi kaydın çıkarılacağını belirler. Bu üçü, taze veri ile yüksek hit oranı arasındaki dengeyi kurar.
SET session:abc "..." EX 3600 # 1 saat TTL
TTL session:abc # → 3600 (kalan saniye)
DEL user:42 # elle invalidation
# bellek dolunca eviction politikası:
maxmemory-policy allkeys-lru # en az son kullanılanı at
maxmemory) gelindiğinde devreye girer.Redis, veriyi diskte değil bellekte tutan bir key-value deposudur; bu yüzden okuma ve yazma mikrosaniyeler sürer. Onu basit bir önbellekten ayıran, zengin veri yapılarıdır: string, hash, list, set, sorted set ve daha fazlası. Tek bir komut akışını sırayla işlediği (single-threaded) için yarış koşulları azdır; istenirse RDB anlık görüntüsü ve AOF günlüğü ile veriyi diske de yazıp yeniden başlatmada geri yükleyebilir.
SET key val # string
HSET user:42 name "Ada" # hash (alanlı nesne)
LPUSH jobs "task1" # list (kuyruk)
SADD tags "redis" # set (benzersiz)
ZADD board 100 "ada" # sorted set (skorlu)
INCR views:home # atomik sayaç
Veri RAM'de tutulduğu için disk erişiminin gecikmesi yoktur. Bedeli, bellek kapasitesiyle sınırlı olması ve verinin uçucu olabilmesidir.
RDB belirli aralıklarla anlık görüntü alır; AOF her yazma komutunu günlüğe ekler. İkisi birlikte, yeniden başlatmada veri kaybını sınırlar.
Komutlar tek tek işlenir; INCR gibi işlemler atomiktir. Bu, sayaç ve kilit gibi senaryoları kilit kullanmadan güvenli kılar.
Redis çoğunlukla "önbellek" diye anılsa da, veri yapıları ve atomik işlemleri sayesinde birçok altyapı sorununu tek başına çözer. Oturum deposu, hız sınırlama, iş kuyruğu, gerçek zamanlı sayaç, lider tablosu ve pub/sub mesajlaşma; hepsi aynı motorun farklı yüzleridir. Çoğu durumda ayrı bir bileşen kurmak yerine zaten elinizdeki Redis'i kullanmak yeterli olur.
Oturumlar TTL'li anahtarlar olarak tutulur; tüm uygulama sunucuları aynı oturumu paylaşır. Ölçeklerken sunucuya yapışkanlık (sticky session) gerekmez.
Atomik INCR ve TTL ile pencere başına istek sayılır. API Tasarımı & Entegrasyon başlığındaki rate limiting'in pratik motoru çoğunlukla budur.
List ve Stream yapıları, arka plan işlerini kuyruğa almak için kullanılır. Sidekiq gibi araçların temelinde Redis kuyrukları yatar.
Sorted set, skora göre sıralı sıralamayı (ranking) tek komutta verir. Gerçek zamanlı puan tabloları ve "en çok okunanlar" listeleri için idealdir.
Kanallara mesaj yayınlanır, aboneler anında alır. Canlı bildirim ve servisler arası hafif mesajlaşma için kullanılır; kalıcılık için Stream tercih edilir.
TTL'li bir anahtar, aynı işin iki sunucuda aynı anda çalışmasını engeller. Basit kilitlerden Redlock desenine kadar bir yelpaze sunar.
Önbellek hız kazandırırken yeni başarısızlık biçimleri de getirir. Saklanan kopya kaynaktan sapabilir (stale veri); bir anahtarın TTL'i dolduğu anda binlerce istek aynı anda kaynağa koşabilir (cache stampede); var olmayan anahtarlar her seferinde DB'ye sızabilir (cache penetration); tek bir popüler anahtar tüm yükü çekebilir (hot key). Bunların her birinin bilinen bir savunması vardır.
Kaynak değişti ama önbellek hâlâ eski kopyayı veriyor. Yazmada invalidation ve makul TTL ile sapmanın süresi sınırlanır.
Popüler bir anahtarın TTL'i dolunca tüm istekler aynı anda DB'ye gider (thundering herd). Tek uçuş kilidi (single-flight) ve TTL'e rastgele sapma (jitter) bunu önler.
Hiç var olmayan anahtarlar her istekte miss üretip DB'yi yorar. "Bulunamadı" sonucunu kısa TTL ile önbelleklemek ya da bloom filter kullanmak çözer.
Tek bir anahtar (ör. ana sayfa) orantısız yük çeker ve tek bir node'u boğar. Yerel önbellek katmanı ya da anahtarı parçalama (sharding) yükü dağıtır.
Çok sayıda anahtarın aynı anda süresi dolar (ya da önbellek çöker) ve tüm yük tek anda kaynağa biner. TTL'leri yaymak ve yedeklilik bu çöküşü engeller.
Önbellek çoğu zaman nihai tutarlılık (eventual consistency) sunar. Mutlak doğruluk gereken veride (ör. bakiye) önbelleği atlamak doğru karardır.
Redis zengin veri yapıları, persistence ve replikasyon sunar; bir önbellekten fazlasıdır. Memcached ise sade, çok iş parçacıklı bir key-value önbelleğidir. Yalnızca basit string önbelleği gerekiyorsa Memcached yeter; veri yapısı ve kalıcılık isteniyorsa Redis öne çıkar.
Cache genel bir kavramdır: veriyi hızlı erişilebilir yerde tutmak. CDN bunun ağ kenarındaki özel bir biçimidir; içeriği coğrafi olarak kullanıcıya yaklaştırır. Redis uygulama içi önbellektir; CDN ise origin'in önündeki dağıtık önbellektir.
TTL planlı bir son kullanma tarihidir: süre dolunca kayıt düşer. Eviction ise bellek dolduğunda yer açmak için kaydı çıkarmaktır. Bir kayıt TTL'i dolmadan da, bellek baskısı yüzünden evict edilebilir.
Write-through önbelleğe ve DB'ye eşzamanlı yazar; tutarlı ama yavaştır. Write-behind önce önbelleğe yazıp DB'ye asenkron işler; hızlı ama önbellek çökerse veri kaybı riski taşır. Fark, yazmanın anında mı yoksa sonradan mı kalıcılaştığıdır.
Caching veriyi hız için geçici tutar; kaybolması tolere edilebilir. Persistence ise veriyi kalıcı ve güvenilir saklamaktır. Redis ikisini de yapabilir ama bir önbellek olarak kullanılan Redis, tek doğru veri kaynağı sayılmamalıdır.
Redis ve Memcached'in resmi dokümantasyonu, HTTP önbelleğini tanımlayan IETF RFC'si ve MDN gibi tarafsız teknik referanslar.
Doğru kurulmuş bir önbellek, aynı donanımdan kat kat fazla iş çıkarır; yanlış kurulmuş bir önbellek ise gizli hatalar üretir. Nereye, hangi desenle ve hangi TTL ile önbellek koyacağınıza birlikte bakalım.