İnsan dolaşım sisteminde kalpten çıkan yüksek basınçlı kan akımı, elastik yapısıyla şok emici görevi gören ana aort damarı tarafından karşılanır. Aort, her sistolde genişleyip diyastolde kasılarak kanın dokulara ve kırılgan kılcal damarlara (kapiller ağ) düzenli, sakin ve tolere edilebilir bir debiyle ulaşmasını sağlar. Şimdi bu tampon görevi gören ana aort duvarının aniden yırtıldığını (aort diseksiyonu) ya da ameliyat sırasında konulan hemostatik tamponun kontrolsüzce çekildiğini düşünün. Yüksek debili, devasa hacimli arteriyel kan aniden doğrudan incecik kapiller yatağa hücum eder. Kılcal damarlar bu devasa basınca saniyeler bile dayanamaz; patlar, parçalanır ve hasta dakikalar içinde masif iç kanamayla geri döndürülemez bir kardiyovasküler kollapsa girer.

Yüksek trafikli web uygulamalarında ve e-ticaret platformlarında Redis veya Memcached gibi bellek içi (in-memory) önbellek katmanları tam olarak bu aort görevi görür. Ana veritabanını (MySQL, PostgreSQL) saniyede gelen on binlerce acımasız SELECT sorgusunun yıkıcı basıncından korur.

Ancak bir gün RAM dolduğu için OOM Killer devreye girerse, Redis servisi çökerse veya tüm önbellek anahtarları aynı saniyede zaman aşımına (TTL Expiry) uğrarsa ne olur? Bilişim dünyasının en yıkıcı zincirleme reaksiyonu tetiklenir: Cache Stampede (Önbellek İzdihamı / Thundering Herd).


Önbellek İllüzyonu: Sahte Güvenlik Hissi

Modern e-ticaret mimarilerinde performans testleri yapılırken genellikle önbelleğin sıcak (warm cache) olduğu varsayılır.

  • Ana sayfa ürün listesi, kategoriler, menüler, en çok satanlar listesi Redis'tedir.
  • İstemci istek atar; istek Nginx'ten Node.js/PHP uygulamasına gelir. Uygulama Redis'e bakar (GET homepage_products), veriyi 2 milisaniyede bellekten çeker ve kullanıcıya HTML basar.
  • Bu senaryoda MySQL sunucusu adeta tatildedir. CPU kullanımı %2, IOPS tüketimi sıfırdır. Sistem mühendisleri "Saniyede 50.000 isteği rahatça kaldırıyoruz" diyerek gururlanır.

Oysa bu bir mühendislik başarısı değil, kırılgan bir illüzyondur. Çünkü altyapı, Redis'in olmadığı bir dünyayı hiç simüle etmemiştir.

NORMAL AKIŞ (Warm Cache):
[50.000 İstek/sn] ───► [Nginx / App] ───► [Redis (%99.9 Hit)] ───► İstemciye Yanıt (2ms)
                                                │
                                                ▼ (Yalnızca %0.1 Miss)
                                         [MySQL: CPU %2]

ÇÖKÜŞ ANI (Cache Stampede):
[50.000 İstek/sn] ───► [Nginx / App] ───► [Redis: ÇÖKTÜ / RESTART ATTI!]
                                                │
                                                ▼ (TÜM İSTEKLER AYNI SANİYEDE)
                                         [MySQL: CPU %100 - MAX CONNECTIONS - DÖNGÜSEL KİLİT!]

Cache Stampede Patolojisi: Dakika Dakika Yıkım

Pazartesi akşamı büyük bir kampanya başlatılmıştır. Sitede anlık 25.000 aktif ziyaretçi vardır.

  1. T = 0. Saniye (Tetikleyici):
    Redis sunucusunun RAM'i dolar. Yapılandırmada maxmemory-policy düzgün ayarlanmadığı için Linux Kernel'ın OOM Killer mekanizması Redis sürecini öldürür (SIGKILL). Servis yöneticisi (systemd) Redis'i hemen yeniden başlatır; ancak ayağa kalkan Redis'in belleği bomboştur (Cold Cache).
  2. T + 1. Saniye (Dalga Geliyor):
    Aynı saniye içinde siteye gelen 10.000 kullanıcı ana sayfayı yeniler. Uygulama kodundaki o klasik acemi mantık çalışır:
    // Çoğu projede yazılan intihar kodu:
    $products = $redis->get('homepage_products');
    if (!$products) {
        // Redis'te yoksa veritabanından çek ve Redis'e yaz!
        $products = $db->query("SELECT * FROM products JOIN categories ... ORDER BY id DESC");
        $redis->set('homepage_products', $products, 3600);
    }
  3. T + 2. Saniye (Kılcal Damarlar Patlıyor):
    Aynı saniyede gelen 10.000 PHP/Node süreci Redis'te anahtarı bulamaz. Bu 10.000 işlemin TAMAMI AYNI ANDA veritabanına karmaşık JOIN'li ana sayfa sorgusunu fırlatır!
  4. T + 5. Saniye (Kollaps):
    MySQL'in varsayılan bağlantı havuzu (max_connections = 151 veya 500) anında tükenir. Konsol feryat eder: ERROR 1040 (HY000): Too many connections.
    Veritabanı sunucusunun CPU'su anında %100'e vurur, disk I/O kuyruğu (wait) tavan yapar.
  5. T + 10. Saniye (Zincirleme Organ İflası):
    Veritabanı yanıt veremediği için arkadaki web servislerinin (PHP-FPM worker'ları) bağlantıları askıda kalır. Nginx upstream kuyruğu dolar ve kullanıcılara 502 Bad Gateway ile 504 Gateway Time-out basmaya başlar.
  6. Mühendisin Çaresizliği:
    Sistem yöneticisi Nginx'i yeniden başlatır; düzelmez. PHP'yi yeniden başlatır; düzelmez. MySQL'i yeniden başlatır; MySQL açılır açılmaz kuyrukta bekleyen binlerce yeni istek tekrar vurur ve MySQL açıldığı saniye yeniden kilitlenir!

Masadaki hasta arrest olmuştur; her elektroşokta ritim daha da bozulmaktadır.


Klinik Tedavi: Çözüm Mimarisinin Reçetesi

Bir önbellek çöküşünün ana veritabanını öldürmesini engellemek, acemi kod bloklarını ortadan kaldırıp kurumsal mimari kalıplarını (architectural design patterns) uygulamakla mümkündür.

1. Karşılıklı Dışlama Kilidi (Mutex / Distributed Locking)

Eğer bir veri önbellekte yoksa, o veriyi veritabanından çekme hakkı o anki 10.000 istekten SADECE BİRİNE verilmelidir. Diğer 9.999 istek o tek sürecin veritabanından veriyi alıp Redis'e yazmasını beklemelidir.

// Dağıtık Kilit (Mutex) Yaklaşımı:
$products = $redis->get('homepage_products');
 
if (!$products) {
    // Sadece 1 iş parçacığının kilit almasına izin ver (5 saniyelik atomik kilit)
    $lockAcquired = $redis->set('lock:homepage_products', '1', ['NX', 'EX' => 5]);
    
    if ($lockAcquired) {
        // YALNIZCA BU İŞLEM VERİTABANINA GİDER!
        $products = $db->query("SELECT * FROM products ...");
        $redis->set('homepage_products', $products, 3600);
        $redis->del('lock:homepage_products');
    } else {
        // Diğer 9.999 işlem veritabanını vurmaz, 100ms bekleyip Redis'i tekrar okur
        usleep(100000); // 100ms
        $products = $redis->get('homepage_products');
    }
}

Bu kilit sayesinde veritabanına aynı anda 10.000 sorgu değil, sadece 1 sorgu gider. Veritabanının haberi bile olmaz.


2. Olasılıksal Erken Yenileme (Probabilistic Early Expiration / XFetch)

Önbellek anahtarlarının belirli bir saniyede (örneğin tam 3600. saniyede) birdenbire yok olması yerine, süre dolmadan hemen önce rastlantısal olarak arka planda yenilenmesi algoritmasıdır.

Bu formül literatürde XFetch algoritması olarak bilinir. Bir istek geldiğinde, anahtarın kalan yaşam süresi (TTL) ve veritabanı sorgu maliyeti hesaplanır. Süre dolmaya yaklaştıkça gelen herhangi bir şanslı istek arka planda asenkron olarak veritabanına gidip önbelleği tazeler. Anahtar hiçbir zaman sıfırlanmaz; önbellek daima sıcak kalır.

3. TTL Jitter (Rastgele Zaman Dağıtımı)

Geliştiricilerin yaptığı en yaygın hatalardan biri, gece saat 00:00'da tüm ürünleri önbelleğe yazarken hepsine TTL = 3600 vermektir. Bu, tam 1 saat sonra tüm ürünlerin önbelleğinin aynı milisaniyede silineceği anlamına gelir.

Anahtarlara TTL verirken her zaman rastgele bir sapma payı (jitter) eklenmelidir:

# Hatalı:
ttl = 3600
 
# Doğru (TTL Jitter):
import random
ttl = 3600 + random.randint(-300, 300) # 3300 ile 3900 saniye arasında dağıtılır

Bu sayede anahtarların düşüşü zamana yayılır; veritabanı anlık bir tsunamiyle değil, sakin bir çisentiyle karşılaşır.


4. Circuit Breaker (Devre Kesici) Deseni

Eğer ana veritabanının yanıt süreleri 200 milisaniyenin üzerine çıkarsa veya hata oranı %5'i geçerse, devre kesici (Resilience4j / Istio / Envoy) otomatik olarak devreyi açmalıdır (Open State).

Veritabanına yeni sorgu göndermek tamamen durdurulur. Kullanıcıya veritabanını kitleyecek ağır sorgular yerine:

  • Statik bir yedek veri (stale cache),
  • Basitleştirilmiş bir ürün listesi,
  • Veya "Şu an yoğunluk nedeniyle sepet işlemleri kısa süreliğine kuyruğa alınmıştır" nezaket sayfası sunulur.

Veritabanı boğularak ölmekten kurtarılır; sistem nefes aldığında devre otomatik olarak kapanır (Closed State).

Sonuç

Önbellek katmanları harika birer amortisördür; ancak süspansiyon sisteminiz çöktüğünde aracınızın şasisi asfalta çarpıp parçalanıyorsa ortada bir mühendislik kusuru vardır.

Bir sistemi "Redis varken çok hızlı" diye tasarlamak yetmez; gerçek mühendislik, "Redis öldüğü an bu sistem ayakta kalabiliyor mu?" sorusuna verilen yanıtta gizlidir. Aortunuzu sağlam tutun, ama kılcal damarlarınızı da doğrudan tazyikli kanla patlatmayacak kilit mekanizmalarını mimarinize mutlaka yerleştirin.