İçeriğe geç
Muhammet Şafak
en
Soran: Cem Cevaplandı:

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


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?

Cevap

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.

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 amacı DB’yi korumakken, expire ânı tam tersini yapıp tüm yükü tek saniyeye sıkıştırıyor.

  1. Tek seferlik mutex (single-flight) lock. 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; diğerleri o sırada ya kısa süre stale veriyi sunar ya da bekleyip yeni değeri okur. Böylece Postgres’e tek sorgu gider, yüzlercesi değil. Kilide her zaman TTL koy ki recompute eden süreç ölse bile kilit kalıcı kilitlenmesin.
  2. Probabilistic early expiration (XFetch). Her okuyucu, TTL bitimine yaklaştıkça, recompute maliyetiyle orantılı bir olasılıkla “ben erken yenileyeyim mi?” diye rastgele karar verir. Yenileme tek ana toplanmadan, herd hiç oluşmadan dağıtılır. Recompute pahalı ve trafik çok yüksekse en zarif çözüm budur.
  3. TTL’lere jitter ekle. Tüm anahtarlara sabit 10 dk verirsen hepsi senkron expire olur — kıyameti birlikte koparırlar. 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ç.
  4. Stale-while-revalidate ile kullanıcıyı bekletme. Anahtar expire olunca eldeki eski değeri sunmaya devam et, yenilemeyi arka planda yap. Kullanıcı asla recompute’u beklemez; lock alan süreç sessizce cache’i tazeler. Bu, lock yaklaşımının “bekleyenler” maliyetini de sıfıra indirir.

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; daha zariftir ama uygulaması ve test etmesi daha incedir. Ve hangisini seçersen seç, stale-while-revalidate’i ekle: kullanıcıyı bir DB sorgusunun arkasında asla bekletme.

Etiketler: #performans#redis#cache
Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi