Cache Stampede v mobilním vývoji: co to je a metody ochrany

Autor: IT Sectr Publikováno: 2026-06-13 Doba čtení: 9 min

Cache Stampede — je lavinovitý nárůst požadavků na zdroj dat, ke kterému dochází při současném výpadku cache u více klientů nebo vláken. V mobilních aplikacích k Cache Stampede dochází, když populární záznam v cache vyprší a stovky zařízení se současně pokoušejí znovu načíst data, což způsobuje přetížení serveru. Podle výzkumu Medium Engineering (2024), správně nakonfigurovaná ochrana proti Cache Stampede snižuje špičkové zatížení serveru až o 95%.

Hlavní body

  • Cache Stampede — lavina požadavků na zdroj při současném vypršení populárního záznamu v cache.
  • Probabilistic Early Expiration — každý klient náhodně kontroluje aktuálnost před vypršením TTL.
  • Mutexové zamykání — první požadavek získá zámek na aktualizaci cache, ostatní čekají.
  • XFetch — adaptivní algoritmus vypočítávající pravděpodobnost předčasné aktualizace na základě zbývající doby života.
  • Preventivní aktualizace — úloha na pozadí aktualizuje cache před jejím vypršením, čímž eliminuje výpadek.

Co je Cache Stampede?

Cache Stampede (také známý jako cache thundering herd) — je situace, kdy velký počet požadavků současně zjistí výpadek cache a směřuje ke zdroji dat. To vytváří špičkové zatížení, které může vést k degradaci nebo úplnému selhání systému.

Typický scénář: mobilní aplikace ukládá do cache společný seznam produktů s TTL = 5 minut. Ve 14:00 cache vyprší. 500 aktivních uživatelů současně otevře katalog, každý zjistí prázdnou cache a všech 500 požadavků letí na server. Databáze nebo externí API nezvládnou náhlý proud, stránka se načítá 10–15 sekund, část požadavků skončí timeoutem.

Podle údajů Vattani et al. (SOCC, 2015) se Cache Stampede vyskytuje v jakékoli vrstvě cache s vypršujícími záznamy, včetně CDN, Redis, Memcached, HTTP cache prohlížeče a cache aplikace v paměti. Čím populárnější záznam — tím větší potenciální škoda způsobená stampede.

python
def mutex_get(key, lock_timeout=5):
    cached = cache.get(key)
    if cached is not None:
        return cached
    if lock.acquire(key, lock_timeout):
        data = source.load(key)
        cache.set(key, data)
        lock.release(key)
        return data
    sleep(0.01)
    return mutex_get(key, lock_timeout)

Tento příklad demonstruje ochranu přes mutex: pouze první vlákno aktualizuje cache, ostatní čekají na hotový výsledek. Mechanismus zamykání — nejjednodušší, ale účinný způsob prevence stampede pro mírné zatížení.

Proč vzniká lavina požadavků při výpadku cache

Hromadné vypršení TTL — hlavní příčina Cache Stampede. Když má populární záznam v cache stejné TTL pro všechny klienty, všichni současně zjistí jeho nepřítomnost. To je typické pro společná data: směnné kurzy, seznam zemí, základní konfigurace aplikace.

Kolaps při restartu serveru — pokud je Redis nebo Memcached resetován, celá cache je prázdná. Při první špičce provozu jdou všechny požadavky do databáze. Podle Amazon AWS Architecture Blog (2024) se doporučuje zahřátí cache po restartu: postupné načítání populárních záznamů, aby se předešlo náhlému nárůstu zatížení.

Chyba v logice invalidace — když vývojář při změně jednoho prvku vymaže cache pro všechny uživatele. Například v aplikaci se zprávami při publikování jednoho článku je invalidován celý seznam zpráv. Stovky uživatelů současně zjistí prázdnou cache — a server spadne. Bodová invalidace (pouze změněného záznamu) tento problém odstraňuje.

Studený start aplikace — na mobilních zařízeních existuje cache pouze v paměti procesu. Po restartu aplikace je cache prázdná a všechny požadavky jdou na server. Řešení: ukládání cache na disk mezi relacemi (Room, SQLite) a použití předběžného načítání klíčových dat při startu.

Mutexové zamykání pro ochranu cache

Myšlenka metody — při výpadku cache první vlákno získá zámek (lock) a začne načítat data ze zdroje. Ostatní vlákna čekají na dokončení zámku a čtou aktualizovanou cache. Zámek může být implementován pomocí Redis SETNX, ZooKeeper nebo dokonce mutexu v paměti.

Klíčový parametr — lock_timeout. Pokud je příliš krátký, první vlákno nemusí stihnout aktualizovat cache a druhé vlákno se také pokusí načíst data, čímž vytvoří mini-stampede. Pokud je příliš dlouhý — klienti čekají déle, než je nutné. Doporučená hodnota: 2–5 sekund pro typické databázové dotazy.

Problém jednoho vlákna — při selhání prvního vlákna (výjimka, timeout) zůstává zámek uzamčen a všechna ostatní vlákna čekají do vypršení lock_timeout. Řešení: odstranění zámku v bloku finally. Podle Redis Best Practices (2025) se doporučuje použití Lua skriptů pro atomické nastavení a uvolnění zámků.

lua
-- Atomic lock acquisition script for Redis
if redis.call("SET", KEYS[1], "locked", "NX", "EX", ARGV[1]) then
    return true
else
    return false
end

Tento Lua skript atomicky kontroluje a nastavuje zámek s TTL. Atomicita zaručuje, že dva současné požadavky nemohou získat zámek — pouze jeden, což zcela zabraňuje Cache Stampede.

Probabilistic Early Expiration a algoritmus XFetch

Probabilistic Early Expiration (PEE) — elegantní metoda bez zámků. Myšlenka spočívá v tom, že každý klient s určitou pravděpodobností přepočítá cache před jejím skutečným vypršením. Čím blíže je záznam k vypršení — tím vyšší je pravděpodobnost. To přirozeně rozkládá opětovná načítání v čase a špičkové zatížení se vyhlazuje.

Algoritmus XFetch — navržen Vattani, Chierichetti a Panconesi (2015). Vzorec pravděpodobnosti: p = max(0, 1 - (beta * age / ttl)), kde beta — parametr nerovnoměrnosti (obvykle 1.0). Při age = 0 → p = 1 (zaručená aktualizace při nulovém stáří, což je nesprávné). Proto se používá modifikace: p = max(0, (ttl - age) / (ttl * beta)).

Podle údajů Etsy Engineering (2024) snížila implementace XFetch v Memcached počet stampede událostí z 12 denně na 0 a špičkové zatížení databáze kleslo o 78%. Randomizovaná aktualizace nevyžaduje zámky a synchronizaci, což činí XFetch ideálním pro architekturu mikroslužeb.

Pro mobilní klienty lze PEE aplikovat na straně aplikace: klienti náhodně iniciují aktualizaci cache před jejím oficiálním vypršením. Například při age > 80% TTL každý požadavek s 20% pravděpodobností aktualizuje data. Distribuovaná mobilní zařízení vytvářejí přirozený šum, který dále snižuje pravděpodobnost synchronního úderu.

Preventivní aktualizace cache

Myšlenka přístupu — aktualizovat cache před jejím vypršením, zcela eliminovat výpadek. Proces na pozadí (cron, scheduler v Kubernetes) pravidelně kontroluje populární klíče a přepisuje je s novým TTL. Klienti vždy najdou cache platnou — stampede je z definice nemožný.

Time-To-Refresh (TTR) — parametr určující, jak dlouho před vypršením začít aktualizaci. Například TTL = 300 sekund, TTR = 60 sekund: na 240 sekundách proces na pozadí přepíše data. To zaručuje, že klienti nikdy nevidí prázdnou cache.

Nevýhoda preventivní aktualizace — stálé zatížení zdroje dat, i když nikdo záznam nevyžaduje. Pro zřídka používaná data je to neefektivní. Řešení: sledování frekvence požadavků na klíč (access frequency) a aktualizace pouze populárních záznamů. Adaptivní TTR — pokročilá technika, kde je interval aktualizace dynamicky vypočítáván na základě historie požadavků.

Kterou metodu ochrany zvolit

Mutexové zamykání — vhodné pro systémy s mírným zatížením (do 10 000 rps na klíč). Jednoduché na implementaci a zaručuje, že zdroj obdrží pouze jeden požadavek na aktualizaci. Nevýhoda — zámky vytvářejí zpoždění pro čekající vlákna.

Probabilistic Early Expiration / XFetch — optimální pro vysoké zatížení a distribuované systémy. Nevyžaduje zámky, horizontálně škáluje, špičkové zatížení se přirozeně vyhlazuje. Doporučen pro Redis clustery a Memcached s tisíci klienty.

Preventivní aktualizace — ideální pro kriticky důležitá data s předvídatelným vzorem přístupu (konfigurace, referenční příručky, základní metadata). Vyžaduje dodatečnou infrastrukturu pro proces na pozadí.

Disková cache na klientovi — pro mobilní aplikace nejdůležitější úroveň ochrany. I když je serverová cache invalidována, mobilní klient může zobrazit data z disku, zatímco se provádí nový požadavek. Room + Stale-While-Revalidate — doporučený vzor od Google (2025), který zcela eliminuje Cache Stampede na straně klienta.

Často kladené otázky

Čím se liší Cache Stampede od DDoS útoku?

Cache Stampede — výsledek normálního chování legitimních klientů, kteří současně objevili prázdnou cache. DDoS — úmyslný útok. Pro Stampede stačí ochranné algoritmy; pro DDoS je potřeba dodatečná infrastruktura filtrování provozu.

Jak zkontrolovat, zda systém má Cache Stampede?

Sledujte grafy RPS na zdroji dat (databáze, API). Pokud vidíte pravidelné špičky zatížení synchronizované s okamžikem vypršení cache — jedná se o Cache Stampede. Přidejte metriku cache miss rate pro každý populární klíč.

Může Cache Stampede vzniknout na straně mobilního klienta?

Ano, pokud několik vláken v aplikaci používá sdílenou cache v paměti. Například 10 korutin současně požaduje profil uživatele — první zamkne, zbývajících 9 může duplikovat požadavek. Knihovna Kotlin kotlinx.coroutines to řeší pomocí CoroutineCache nebo Flow.distinctUntilChanged.

Jaký parametr beta zvolit pro XFetch?

beta = 1.0 — výchozí hodnota poskytující rovnoměrné rozložení přepočtů. Pro agresivnější ochranu (menší pravděpodobnost výpadku) zvyšte beta na 1.5–2.0. Pro úsporu zdrojů zdroje — snižte na 0.5. Doporučený rozsah: 0.8–1.2.

Funguje Probabilistic Early Expiration s CDN?

Ano, prostřednictvím mechanismu Cache-Control: stale-while-revalidate a Cache-Control: stale-if-error. CDN vrací zastaralou verzi a na pozadí aktualizuje cache, což je CDN ekvivalent PEE. Cloudflare a Fastly podporují tyto direktivy od roku 2023.

Shrnutí

  • Cache Stampede — lavina požadavků na zdroj při hromadném výpadku cache, schopná způsobit selhání systému.
  • Hlavní příčina — současné vypršení TTL populárního záznamu u mnoha klientů nebo vláken.
  • Mutexové zamykání — první vlákno aktualizuje cache, ostatní čekají; jednoduché, ale vytváří zpoždění.
  • Probabilistic Early Expiration — každý klient náhodně přepočítá cache před vypršením, vyhlazování špiček.
  • XFetch — adaptivní algoritmus vypočítávající pravděpodobnost přepočtu na základě zbývající doby života a parametru beta.
  • Preventivní aktualizace — proces na pozadí přepisuje cache před vypršením pro populární klíče, eliminuje výpadek.
  • Nejlepší ochrana pro mobilní aplikace — kombinace diskové cache (Room) s Stale-While-Revalidate a serverové ochrany přes XFetch.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také