Cache doğru kurulduğunda maliyeti düşürür, gecikmeyi azaltır, sistemi sakinleştirir. Yanlış kurulduğunda ise tam tersi olur: cache TTL’i biter, bir anahtar “soğur”, aynı anda binlerce istek backend’e akar ve backend ölmeden önce cache öldürür.
Bu yazı, stampede (thundering herd) problemini “teori” değil sahada uygulanabilir kontrol mekanizmaları ile ele alır.
1) Stampede nasıl görünür?
Tipik sinyaller:
- Cache hit ratio aniden düşer
- Backend QPS / DB bağlantıları fırlar
- p95/p99 latency artar, sonra timeout dalgası gelir
- Hata kodları: 5xx + “upstream timeout” + “connection pool exhausted”
En tehlikeli senaryo: tek bir sıcak key (homepage payload, kampanya fiyatı, auth policy) TTL bitiminde binlerce istemci tarafından aynı anda istenir.
2) Root cause: TTL senkronu ve eşzamanlı yenileme
Stampede genelde şu kombinasyonla başlar:
- Tüm node’lar aynı TTL’i kullanır (senkron bitiş)
- Cache miss’te herkes backend’e gider (coalescing yok)
- Backend’in koruması yoktur (rate limit / circuit breaker yok)
3) Birinci savunma: TTL jitter (senkronu boz)
TTL’i sabit tutmayın. Aynı “ürün sınıfı” için bile küçük jitter uygulayın:
- Örn. 300 saniye yerine 240–360 arası rastgele
- Key bazında deterministik jitter da olur (hash ile)
Ama tek başına yetmez: jitter, dalgayı dağıtır; yenilemeyi tekilleştirmez.
4) İkinci savunma: Request coalescing (singleflight)
Cache miss olduğunda, aynı key için aynı anda gelen istekleri tek bir “yenileme işi”ne bağlayın:
- İlk istek backend’e gider
- Diğerleri aynı sonucu bekler (veya eski veriyi alır)
Uygulama tarafında bu mantık genelde singleflight/memoize/promise cache olarak kurulur.
Operasyonel not: Coalescing’in “wait” süresi için üst sınır koyun. Backend bozulduysa tüm request’leri kilitlemeyin.
5) Üçüncü savunma: Stale-while-revalidate (serve stale)
Kritik key’lerde “tam doğru” yerine “kabul edilebilir eski”yi servis etmek, incident’i bitirir.
Model:
- TTL bittiğinde, kısa bir “stale window” içinde eski değeri dön
- Arkadan yenilemeyi başlat
- Yenileme başarısızsa, eski değeri sınırlı süre daha kullan
Bu yaklaşımın pratik sonucu: backend kısa süreli dalgalanmalarda “yıkılmadan” toparlanır.
6) Dördüncü savunma: Backend korumaları (sınırla ve döndür)
Stampede anında backend’i korumak için:
- Rate limit: key veya endpoint bazında
- Bulkhead: cache miss trafiğine ayrı havuz/queue
- Circuit breaker: hata/timeout artınca hızlı fail
- Load shedding: düşük öncelikli talepleri kıs
Buradaki hedef: “her isteği cevapla” değil, sistemi ayakta tut.
7) Runbook: stampede başladığında ne yaparım?
Sahada 15–30 dakikalık pratik sıra:
- Hangi key/endpoint patlıyor? (top keys / top routes)
- Cache layer: hit ratio, evictions, TTL davranışı
- Backend: pool doluluğu, timeouts, error rate
- Hızlı müdahale:
- Serve stale aç (varsa)
- Miss trafiğine rate limit uygula
- TTL’i geçici artır (veya cache warm-up)
- En kritik key’leri precompute/prewarm et
- Kalıcı düzeltme:
- Coalescing + jitter + stale modelini kod seviyesine al
- Operasyon testini ekle: “cache flush sonrası dayanıklılık”
8) Test: “cache flush chaos” küçük ama çok değerli
Benim sevdiğim pratik test:
- Canary ortamında belirli key setini purge et
- Aynı anda N istek üret (kademeli)
- Backend’in davranışını ölç
Bu test, cache stratejisini “güzel günde hızlı” olmaktan çıkarıp “kötü günde güvenli” hale getirir.
9) Son söz
Cache stampede, çoğu zaman “cache yok” probleminden daha pahalıdır; çünkü görünürde cache vardır ama kriz anında sistemi korumaz. TTL jitter, coalescing ve stale stratejilerini birlikte uyguladığınızda cache, performans aracından operasyonel emniyet kemerine dönüşür.