irdaweb Bilgi Teknolojileri
Telefon numaramız +90 541 209 02 05
E-posta adresimiz [email protected]
Konu 18 · Önbellekleme & Redis

Önbellekleme ve Redis — cache layer, pattern ve TTL.

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.

01 — Temeller

Önbellekleme nedir, cache hit ve miss nasıl çalışır?

Ö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.

Cache-aside hit / miss akışı
# 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
HITCache hit — hızlı yol

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.

MISSCache miss — yavaş yol

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).

RatioHit ratio — ölçü

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.

02 — Önbellek katmanları

Veri nerede önbelleklenir: tarayıcıdan veritabanına

Ö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.

Katmanlar kullanıcıya yakından uzağa
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.

Tarayıcı & HTTP önbelleği

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.

CDN & edge önbelleği

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.

Uygulama önbelleği (Redis)

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.

03 — Önbellekleme desenleri

Cache-aside, read-through ve write-through

Ö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
Cache-aside Uygulama
Read-through Önbellek katmanı
Write-through Önbellek katmanı
Write-behind Önbellek katmanı
Cache-aside

Lazy loading

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.

Write-through

Eşzamanlı yazma

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.

Write-behind

Geciktirilmiş yazma

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.

04 — TTL & invalidation

TTL, invalidation ve eviction politikaları

Ö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.

Redis CLI TTL & eviction
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
TTL
Time to live — kaydın ömrü. Süre dolunca kayıt otomatik düşer. Kısa TTL veriyi taze tutar ama hit oranını düşürür; uzun TTL tersini yapar. Çoğu önbellek için en pratik tazeleme aracıdır.
Invalidation
Veri değiştiği anda ilgili anahtarı silmek. En doğru ama en zor yöntem: hangi anahtarların etkilendiğini bilmek gerekir. "Bilgisayar bilimindeki iki zor şeyden biri" denmesi boşuna değildir.
LRU / LFU
Eviction politikaları. LRU en uzun süredir kullanılmayanı, LFU en az sıklıkta kullanılanı atar. Bellek sınırına (maxmemory) gelindiğinde devreye girer.
Eviction
Bellek dolduğunda yeni veriye yer açmak için eski kaydı çıkarma. TTL dolması ile karıştırılmamalı: eviction bir bellek baskısı tepkisidir, TTL ise planlı bir son kullanma tarihidir.
05 — Redis temelleri

Redis: in-memory veri yapıları ve persistence

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.

Veri yapıları temel komutlar
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ç

In-memory — neden hızlı

Veri RAM'de tutulduğu için disk erişiminin gecikmesi yoktur. Bedeli, bellek kapasitesiyle sınırlı olması ve verinin uçucu olabilmesidir.

Persistence — RDB & AOF

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.

Single-threaded & atomik

Komutlar tek tek işlenir; INCR gibi işlemler atomiktir. Bu, sayaç ve kilit gibi senaryoları kilit kullanmadan güvenli kılar.

06 — Redis senaryoları

Redis'in önbellek dışında kullanıldığı yerler

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.

Session store

Oturum deposu

Oturumlar TTL'li anahtarlar olarak tutulur; tüm uygulama sunucuları aynı oturumu paylaşır. Ölçeklerken sunucuya yapışkanlık (sticky session) gerekmez.

Rate limiting

Hız sınırlama

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.

Queue

İş kuyruğu

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.

Leaderboard

Lider tablosu

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.

Pub/Sub

Yayınla-abone ol

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.

Distributed lock

Dağıtık kilit

TTL'li bir anahtar, aynı işin iki sunucuda aynı anda çalışmasını engeller. Basit kilitlerden Redlock desenine kadar bir yelpaze sunar.

07 — Tutarlılık & tuzaklar

Stale veri, cache stampede ve hot key sorunları

Ö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.

Stale data

Eskimiş veri

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.

Stampede

Cache stampede

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.

Penetration

Cache penetration

Hiç var olmayan anahtarlar her istekte miss üretip DB'yi yorar. "Bulunamadı" sonucunu kısa TTL ile önbelleklemek ya da bloom filter kullanmak çözer.

Hot key

Sıcak anahtar

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.

Avalanche

Cache avalanche

Ç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.

Consistency

Tutarlılık tercihi

Ö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.

Önbellek, doğruluk değil hız katmanıdır. Bir önbelleğin düşmesi uygulamayı yavaşlatmalı, durdurmamalı; kaynak her zaman tek doğru veri (source of truth) olarak ayakta kalmalıdır. Önce kaynağı doğru kurun, önbelleği sonra ekleyin.
08 — Sık karıştırılanlar

Sık karıştırılan önbellekleme kavramları

Redis vs. Memcached

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 vs. CDN

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 vs. Eviction

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 vs. Write-behind

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 vs. Persistence

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.

Birinci el kaynaklar

Redis ve Memcached'in resmi dokümantasyonu, HTTP önbelleğini tanımlayan IETF RFC'si ve MDN gibi tarafsız teknik referanslar.

Sıradaki adım

Önbellek katmanınızı birlikte tasarlayalım.

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.