# Redis cache stampede'i (thundering herd) nasıl önlerim — mutex lock mı, XFetch mi?

> Çoğu durumda single-flight lock ve TTL jitter yeter; XFetch'i recompute gerçekten pahalıyken açın ve her iki hâlde stale-while-revalidate ekleyin.

- Soruldu: 2026-05-16
- Yanıtlandı: 2026-05-19
- Soran: Cem
- Etiketler: performans, redis, caching
- Kaynak: https://muhammetsafak.com/tr/sor-bakalim/redis-cache-stampede-mutex-lock-mu-xfetch-mi/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**Soru:** Yoğun trafikli bir e-ticaretin ana sayfa ürün listesini Redis'te 10 dk önbelleğe alıyoruz. Önbellek tam expire olduğu saniyede gelen binlerce eşzamanlı istek cache miss alıp aynı anda PostgreSQL'e yükleniyor ve DB'yi çökertiyor.

Bu cache stampede'i çözmek için mimari düzeyde mutex lock veya probabilistic early expiration (XFetch) algoritmalarını nasıl uygularım?


Kısa cevap: Sorun "miss"in kendisi değil, anahtarın **aynı saniyede uçurumdan düşmesi** ve tüm sürünün aynı anda DB'ye yüklenmesi. Çözüm, o ânı tek isteğe indirgemek ve sürüyü zamana yaymak.

## Kısa cevap

Yaşadığın şey klasik **thundering herd**: TTL bitince tek bir kullanıcı değil, binlerce istek aynı milisaniyede cache miss alıp aynı sorguyu PostgreSQL'e atıyor. Tek bir sorgu yeterken yüzlercesi koşuyor, bağlantı havuzu doluyor ve DB diz çöküyor. Önbelleğin tazeliğini kimin ittiği sorusunu [edge cache ve invalidation kaydında](/tr/sor-bakalim/cloudflare-workers-kv-ile-edge-cache-ve-invalidation/) ayrıca tartışmıştım; buradaki mesele o tazelemenin **kaç kez** koştuğu.

## Neden

1. **Önbellek expire ânında amacının tersini yapar.** Görevi DB'yi korumakken, tüm yükü tek saniyeye sıkıştırır.

2. **Sabit TTL senkronizasyon üretir.** Tüm anahtarlara aynı 10 dakikayı verirseniz hepsi birlikte düşer; kıyameti beraber koparırlar.

3. **Kullanıcıyı recompute'un arkasında bekletmek gereksiz.** Elinizde bir saniye öncesine ait doğru bir değer varken onu sunmamak için bir sebep yok.

## Ne yapmalı

1. **Tek seferlik mutex (single-flight) lock kur.** Miss anında ilk istek Redis'te kısa bir kilit alır (`SET NX PX` ile, ms cinsinden TTL'li); kilidi alan recompute eder ve cache'i doldurur. Böylece Postgres'e tek sorgu gider. Kilide her zaman TTL koy ki recompute eden süreç ölse bile kilit kalıcı kilitlenmesin.

2. **TTL'lere jitter ekle.** TTL'yi `10dk ± rastgele birkaç dakika` yaparsan anahtarlar farklı anlarda düşer, basınç doğal olarak yayılır. Tek satırlık değişiklik, büyük kazanç.

3. **Stale-while-revalidate ile kullanıcıyı bekletme.** Anahtar expire olunca eldeki eski değeri sunmaya devam et, yenilemeyi arka planda yap. Bu, lock yaklaşımının "bekleyenler" maliyetini de sıfıra indirir.

4. **Recompute gerçekten pahalıysa XFetch'e geç.** Probabilistic early expiration ile her okuyucu, TTL bitimine yaklaştıkça recompute maliyetiyle orantılı bir olasılıkla erken yenilemeye karar verir; herd hiç oluşmaz. Daha zariftir ama uygulaması ve test etmesi daha incedir.

**Sonuç:** Ben olsam çoğu durumda **single-flight lock + TTL jitter** ile başlardım — birlikte vakaların büyük çoğunluğunu kapatır, operasyonu basittir, anlaması kolaydır. XFetch'i recompute gerçekten pahalı ve trafik gerçekten devasaysa devreye al. Ve hangisini seçersen seç, stale-while-revalidate'i ekle: kullanıcıyı bir DB sorgusunun arkasında asla bekletme.

## İlgili Yazılar

- [Redis'te canlı leaderboard için neden Sorted Set kullanmalıyım?](https://muhammetsafak.com/tr/sor-bakalim/redis-veri-tipleri-leaderboard-icin-sorted-set/) — Sor Bakalım
- [Heap erişimini önlemek ve index-only scan almak için covering index'e (INCLUDE) ne zaman geçmeliyim?](https://muhammetsafak.com/tr/sor-bakalim/index-only-scan-covering-indexe-ne-zaman-gecmeliyim/) — Sor Bakalım
- [İşlediğim satırları aynı anda güncellerken chunk yerine chunkById mı kullanmalıyım?](https://muhammetsafak.com/tr/sor-bakalim/isledigim-satirlari-ayni-anda-guncellerken-chunk-yerine-chunkbyid-mi-kullanmaliyim/) — Sor Bakalım
