Cache Stampede i mobilutveckling: vad är det och skyddsmetoder

Författare: IT Sectr Publicerad: 2026-06-13 Lästid: 9 min

Cache Stampede — är en lavinartad ökning av förfrågningar till datakällan som uppstår när flera klienter eller trådar samtidigt upptäcker en cachemiss. I mobilappar uppstår Cache Stampede när en populär cachepost upphör och hundratals enheter samtidigt försöker ladda om data, vilket orsakar överbelastning av servern. Enligt forskning från Medium Engineering (2024) minskar korrekt konfigurerat skydd mot Cache Stampede serverns toppbelastning med upp till 95%.

Huvudpunkter

  • Cache Stampede — lavin av förfrågningar till källan vid samtidig utgång av en populär cachepost.
  • Probabilistic Early Expiration — varje klient kontrollerar slumpmässigt aktualiteten före TTL:s utgång.
  • Mutexlåsning — den första förfrågan får ett lås för att uppdatera cachen, övriga väntar.
  • XFetch — adaptiv algoritm som beräknar sannolikheten för förtida uppdatering baserat på återstående livstid.
  • Förebyggande uppdatering — en bakgrundsuppgift uppdaterar cachen före dess utgång, vilket eliminerar cachemissen.

Vad är Cache Stampede?

Cache Stampede (även känt som cache thundering herd) — är en situation där ett stort antal förfrågningar samtidigt upptäcker en cachemiss och riktas mot datakällan. Detta skapar en toppbelastning som kan leda till degradering eller fullständigt systemhaveri.

Typiskt scenario: en mobilapp cachar en gemensam produktlista med TTL = 5 minuter. Klockan 14:00 upphör cachen. 500 aktiva användare öppnar samtidigt katalogen, var och en upptäcker en tom cache och alla 500 förfrågningar går till servern. Databasen eller externt API klarar inte av den plötsliga strömmen, sidan laddas på 10–15 sekunder, en del av förfrågningarna får timeout.

Enligt data från Vattani et al. (SOCC, 2015) uppstår Cache Stampede i vilket cachelager som helst med upphörande poster, inklusive CDN, Redis, Memcached, webbläsarens HTTP-cache och appens minnescache. Ju populärare posten är — desto större är den potentiella skadan från 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)

Detta exempel visar skydd via mutex: endast den första tråden uppdaterar cachen, övriga väntar på det färdiga resultatet. Låsmekanismen — det enklaste men effektiva sättet att förhindra stampede vid måttliga belastningar.

Varför uppstår en lavin av förfrågningar vid cachemiss

Massiv utgång av TTL — den främsta orsaken till Cache Stampede. När en populär cachepost har samma TTL för alla klienter upptäcker de alla samtidigt dess frånvaro. Detta är typiskt för gemensam data: valutakurser, landslista, grundläggande appkonfiguration.

Kollaps vid serveromstart — om Redis eller Memcached återställs blir hela cachen tom. Vid den första trafiktoppen går alla förfrågningar till databasen. Enligt Amazon AWS Architecture Blog (2024) rekommenderas att värma upp cachen efter omstart: gradvis ladda populära poster för att undvika en plötslig belastningsökning.

Fel i ogiltigförklaringslogiken — när utvecklaren rensar cachen för alla användare vid ändring av ett element. Till exempel i en nyhetsapp vid publicering av en artikel ogiltigförklaras hela nyhetslistan. Hundratals användare upptäcker samtidigt en tom cache — och servern kraschar. Punktvis ogiltigförklaring (endast av den ändrade posten) eliminerar detta problem.

Kallstart av appen — på mobila enheter finns cachen endast i processens minne. Efter omstart av appen är cachen tom och alla förfrågningar går till servern. Lösning: spara cachen på disk mellan sessioner (Room, SQLite) och använd förladdning av nyckeldata vid start.

Mutexlåsning för skydd av cache

Idén med metoden — vid cachemiss tar den första tråden ett lås (lock) och börjar ladda data från källan. Övriga trådar väntar på att låset ska släppas och läser den uppdaterade cachen. Låset kan implementeras via Redis SETNX, ZooKeeper eller till och med en minnesmutex.

Nyckelparametern — lock_timeout. Om den är för kort hinner den första tråden kanske inte uppdatera cachen, och den andra tråden kommer också att försöka ladda data, vilket skapar en mini-stampede. Om den är för lång — väntar klienterna längre än nödvändigt. Rekommenderat värde: 2–5 sekunder för typiska databasförfrågningar.

Problem med en enda tråd — vid fel på den första tråden (undantag, timeout) förblir låset taget och alla andra trådar väntar tills lock_timeout går ut. Lösning: ta bort låset i finally-blocket. Enligt Redis Best Practices (2025) rekommenderas användning av Lua-skript för atomisk inställning och frigöring av lås.

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

Detta Lua-skript kontrollerar och ställer atomiskt in ett lås med TTL. Atomiciteten garanterar att två samtidiga förfrågningar inte kan få låset — bara en, vilket helt förhindrar Cache Stampede.

Probabilistic Early Expiration och XFetch-algoritmen

Probabilistic Early Expiration (PEE) — en elegant metod utan lås. Idén är att varje klient med en viss sannolikhet räknar om cachen före dess faktiska utgång. Ju närmare posten är utgång — desto högre sannolikhet. Detta fördelar naturligt omladdningarna i tiden och toppbelastningen jämnas ut.

XFetch-algoritmen — föreslagen av Vattani, Chierichetti och Panconesi (2015). Sannolikhetsformeln: p = max(0, 1 - (beta * age / ttl)), där beta — ojämnhetsparametern (vanligtvis 1.0). Vid age = 0 → p = 1 (garanterad uppdatering vid noll ålder, vilket är felaktigt). Därför används en modifiering: p = max(0, (ttl - age) / (ttl * beta)).

Enligt data från Etsy Engineering (2024) minskade implementeringen av XFetch i Memcached antalet stampede-händelser från 12 per dag till 0, och databasens toppbelastning minskade med 78%. Randomiserad uppdatering kräver inga lås och synkronisering, vilket gör XFetch idealiskt för mikrotjänstarkitektur.

För mobila klienter kan PEE tillämpas på appsidan: klienter initierar slumpmässigt uppdatering av cachen före dess officiella utgång. Till exempel vid age > 80% TTL uppdaterar varje förfrågan med 20% sannolikhet data. Distribuerade mobila enheter skapar naturligt brus som ytterligare minskar sannolikheten för en synkron stöt.

Förebyggande uppdatering av cache

Idén med angreppssättet — uppdatera cachen innan den upphör, helt eliminera cachemissen. En bakgrundsprocess (cron, scheduler i Kubernetes) kontrollerar periodiskt populära nycklar och skriver över dem med ny TTL. Klienter hittar alltid cachen giltig — stampede är per definition omöjlig.

Time-To-Refresh (TTR) — parameter som bestämmer hur långt före utgång uppdateringen ska påbörjas. Till exempel TTL = 300 sekunder, TTR = 60 sekunder: vid 240 sekunder skriver bakgrundsprocessen över data. Detta garanterar att klienter aldrig ser en tom cache.

Nackdel med förebyggande uppdatering — konstant belastning på datakällan, även om ingen begär posten. För sällan använda data är detta ineffektivt. Lösning: övervaka förfrågningsfrekvensen till en nyckel (access frequency) och uppdatera endast populära poster. Adaptiv TTR — en avancerad teknik där uppdateringsintervallet beräknas dynamiskt baserat på förfrågningshistorik.

Vilken skyddsmetod ska man välja

Mutexlåsning — lämplig för system med måttlig belastning (upp till 10 000 rps per nyckel). Enkel att implementera och garanterar att källan endast får en uppdateringsförfrågan. Nackdel — lås skapar fördröjning för väntande trådar.

Probabilistic Early Expiration / XFetch — optimal för höga belastningar och distribuerade system. Kräver inga lås, skalas horisontellt, toppbelastning jämnas ut naturligt. Rekommenderas för Redis-kluster och Memcached med tusentals klienter.

Förebyggande uppdatering — idealisk för kritisk data med förutsägbart åtkomstmönster (konfigurationer, referensverk, grundläggande metadata). Kräver ytterligare infrastruktur för bakgrundsprocessen.

Diskcache på klienten — för mobilappar den viktigaste skyddsnivån. Även om servercachen ogiltigförklaras kan den mobila klienten visa data från disken medan en ny förfrågan utförs. Room + Stale-While-Revalidate — det rekommenderade mönstret från Google (2025), som helt eliminerar Cache Stampede på klientsidan.

Vanliga frågor

Vad skiljer Cache Stampede från en DDoS-attack?

Cache Stampede — resultatet av normalt beteende hos legitima klienter som samtidigt upptäcker en tom cache. DDoS — en avsiktlig attack. För Stampede räcker skyddsalgoritmer; för DDoS krävs ytterligare infrastruktur för trafikfiltrering.

Hur kontrollerar man om systemet har Cache Stampede?

Övervaka RPS-diagram på datakällan (databas, API). Om du ser regelbundna belastningstoppar synkroniserade med cacheutgångsmomentet — är detta Cache Stampede. Lägg till mätvärdet cache miss rate för varje populär nyckel.

Kan Cache Stampede uppstå på den mobila klientens sida?

Ja, om flera trådar i appen använder en gemensam minnescache. Till exempel begär 10 korutiner samtidigt en användarprofil — den första låser, de övriga 9 kan duplicera förfrågan. Kotlin-biblioteket kotlinx.coroutines löser detta via CoroutineCache eller Flow.distinctUntilChanged.

Vilken beta-parameter ska man välja för XFetch?

beta = 1.0 — standardvärdet som ger en jämn fördelning av omräkningar. För mer aggressivt skydd (mindre sannolikhet för miss) öka beta till 1.5–2.0. För att spara källresurser — minska till 0.5. Rekommenderat intervall: 0.8–1.2.

Fungerar Probabilistic Early Expiration med CDN?

Ja, via mekanismen Cache-Control: stale-while-revalidate och Cache-Control: stale-if-error. CDN returnerar den gamla versionen och uppdaterar cachen i bakgrunden, vilket är CDN-motsvarigheten till PEE. Cloudflare och Fastly stöder dessa direktiv sedan 2023.

Sammanfattning

  • Cache Stampede — lavin av förfrågningar till källan vid massiv cachemiss, som kan orsaka systemhaveri.
  • Främsta orsaken — samtidig utgång av TTL för en populär post hos flera klienter eller trådar.
  • Mutexlåsning — första tråden uppdaterar cachen, övriga väntar; enkelt men orsakar fördröjning.
  • Probabilistic Early Expiration — varje klient räknar slumpmässigt om cachen före utgång, jämnar ut toppar.
  • XFetch — adaptiv algoritm som beräknar sannolikheten för omräkning baserat på återstående livstid och beta-parametern.
  • Förebyggande uppdatering — bakgrundsprocess skriver över cachen före utgång för populära nycklar, eliminerar miss.
  • Bästa skyddet för mobilappar — kombination av diskcache (Room) med Stale-While-Revalidate och serverskydd via XFetch.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också