Hoppa till innehållet

Guider

Så cachar du API:er med hög trafik i Redis och Elasticsearch

· 6 min läsning

Cacha ett API med hög trafik genom att mäta först och sedan lägga ett cache-aside-lager i Redis framför de långsammaste och mest lästa endpoints, med uttryckliga TTL:er, invalidering vid skrivning och skydd mot cache stampede. Använd Elasticsearch för sökningar och filtrerade listor som den primära databasen hanterar dåligt, och cacha aldrig användarspecifika eller strikt konsistenta data utan en genomtänkt design.

Mät P95-latensen innan du lägger till någon cache

Medelvärden döljer de anrop som användarna klagar på. Följ P95- och P99-latensen per endpoint, tillsammans med antalet anrop, så att du ser vilka routes som både är långsamma och används mycket.

Ta sedan reda på var tiden går. En trace eller en enkel tidsuppdelning per anrop visar oftast om kostnaden ligger i en långsam fråga, upprepade frågor, ett anrop till ett externt API eller serialisering. Att cacha ett svar vars egentliga problem är ett saknat index döljer bara problemet till nästa cachemiss.

  • Registrera P50, P95 och P99 per endpoint, inte bara en global siffra
  • Rangordna endpoints efter antal anrop gånger latens för att se var cachning lönar sig mest
  • Kontrollera förhållandet mellan läsningar och skrivningar, eftersom data som läses mycket oftare än de ändras är de bästa kandidaterna
  • Åtgärda saknade index och N+1-frågor innan du cachar runt dem

Använd cache-aside som standardmönster

Med cache-aside kontrollerar applikationen Redis först. Vid en träff returnerar den det cachade värdet. Vid en miss läser den från databasen, skriver resultatet till Redis med en TTL och returnerar det.

Mönstret behåller databasen som den enda sanningskällan och fallerar på ett säkert sätt. Om Redis är långsam eller otillgänglig faller applikationen tillbaka på databasen, med en kort timeout och en circuit breaker så att en cache som har problem inte gör varje anrop långsammare.

Utforma nycklarna medvetet. Ta med resurstyp, identifierare, API-version och varje parameter som ändrar svaret, till exempel språk eller sida. Ett förutsägbart nyckelschema är det som gör riktad invalidering möjlig senare.

Sätt TTL:er efter hur inaktuella data får vara och invalidera vid ändring

En TTL är ett affärsbeslut uttryckt som en siffra. Fråga hur gamla data får vara innan en användare eller ett system längre ned i kedjan tar skada, och sätt TTL:en utifrån svaret. Ett resultat från en pågående match och en arkiverad artikel tål helt olika grader av inaktualitet.

Att bara lita på att nycklar löper ut innebär att inaktuella data serveras tills TTL:en har gått ut. För data som din egen applikation ändrar: radera eller skriv över nyckeln när skrivningen har bekräftats, helst från en händelse som skickas efter transaktionen, så att cachen aldrig innehåller data som databasen har rullat tillbaka.

Lägg till en liten slumpmässig jitter i TTL:erna så att nycklar som skrivs samtidigt inte löper ut i samma ögonblick.

  • Kort TTL på några sekunder för data som ändras snabbt, där lite inaktuella data är acceptabla
  • Längre TTL plus invalidering vid skrivning för data som du styr över och som sällan ändras
  • Versionerade nycklar, där ett höjt versionsnummer invaliderar en hel grupp nycklar på en gång

Skydda databasen mot cache stampede

En stampede uppstår när en populär nyckel löper ut och många samtidiga anrop missar på en gång och alla skickar samma dyra fråga till databasen. På ett API med hög trafik kan det överbelasta databasen precis när trafiken toppar.

Kombinera två eller fler av de här skydden på dina mest använda nycklar.

  • Sammanslagning av anrop (request coalescing): ett anrop bygger om nyckeln under ett kort Redis-lås som sätts med NX och en utgångstid, medan de andra väntar en kort stund eller serverar det tidigare värdet
  • Stale-while-revalidate: spara en mjuk utgångstid i värdet, fortsätt servera den inaktuella kopian efter den och uppdatera i bakgrunden
  • Tidig sannolikhetsbaserad uppdatering: bygg ibland om en het nyckel innan den löper ut, med en sannolikhet som ökar ju närmare utgångstiden är
  • Förvärmning: fyll kända heta nycklar före en planerad trafiktopp, till exempel ett stort liveevenemang

Använd Elasticsearch för sökning och listor, inte som allmän cache

Redis är bäst för uppslag på nyckel och värde: ett enskilt objekt, ett beräknat fragment, en räknare för anropsbegränsning. Elasticsearch passar för ett annat jobb: fritextsökning, facetterade filter och sorterade listor som är dyra att beräkna i en relationsdatabas.

Behandla Elasticsearch-indexet som en läsmodell som matas från den primära databasen, via ändringshändelser eller en schemalagd synkronisering, och acceptera att det blir konsistent först efter en viss fördröjning (eventual consistency). Låt databasen vara den som gäller för skrivningar och för allt som måste vara exakt.

På NorthStar Networks sportmedieplattform, som har 50M+ användare i månaden, byggde våra utvecklare om kritiska API:er och gjorde om cachningen i Redis och Elasticsearch, vilket minskade svarstiderna vid P95.

Vet vad du inte ska cacha

Den dyraste cachebuggen är att servera en användares data till en annan. Kontrollera att identiteten ingår i nyckeln för varje cachad endpoint, och testa med två olika konton före release.

  • Svar som beror på anroparens identitet eller behörigheter, om inte nyckeln innehåller användaren eller rollen
  • Data som måste vara strikt konsistenta, som saldon, lagersaldo i kassan eller allt som används i behörighetsbeslut
  • Endpoints för skrivning, engångstokens och allt som har sidoeffekter
  • Endpoints med låg trafik, där en cache tillför komplexitet och ett nytt sätt att fallera för liten vinst
  • Mycket stora svar som tränger undan många mindre och mer använda nycklar

Gör cachen observerbar, annars kan du inte lita på den

Följ träffkvot per nyckelprefix, Redis minnesanvändning och utträngningar, latensen för Redis-kommandon och databasbelastningen, bredvid API:ets P95 på samma dashboard. När P95 rör sig ska du inom några minuter kunna avgöra om det var cachen, databasen eller en tjänst längre upp i kedjan som orsakade det.

Larma vid ett plötsligt fall i träffkvoten, vilket ofta betyder att en driftsättning har ändrat ett nyckelformat, och vid ökande utträngningar, vilket betyder att cachen är för liten för den data den ska rymma.

Vi tar oss an API-prestanda som ett avgränsat block: mätning, ny design av cachelagret och överlämning av dashboards och runbooks till teamet som driver det.

Det viktigaste

  • Mät P95 per endpoint och åtgärda problem med frågorna innan du lägger till en cache.
  • Cache-aside i Redis är det säkraste standardvalet eftersom databasen förblir sanningskällan.
  • Sätt TTL:er efter hur inaktuella data får vara, och invalidera vid skrivning för data som du styr över.
  • Skydda heta nycklar mot stampede med lås, stale-while-revalidate eller förvärmning.
  • Använd Elasticsearch som en läsmodell med fördröjd konsistens för sökning och listor, inte som allmän cache.

Vanliga frågor

Ska jag använda Redis eller Elasticsearch för att cacha API-svar?

Använd Redis för cachning av objekt, beräknade fragment och räknare på nyckel och värde, eftersom uppslag på nyckel är snabba och enkla att invalidera. Använd Elasticsearch när det dyra är sökning, filtrering eller sortering över många poster, och behandla indexet som en läsmodell snarare än en cache.

Vilken TTL är lämplig för API-svar?

Det finns inget universellt värde. Sätt varje TTL efter hur inaktuella data får vara utan att en användare tar skada, använd några sekunder för data som ändras snabbt och kombinera längre TTL:er med invalidering vid skrivning. Lägg till slumpmässig jitter så att relaterade nycklar inte löper ut samtidigt.

Hur förhindrar jag en cache stampede i Redis?

Låt bara ett anrop bygga om en utgången nyckel genom att ta ett kort lås med SET och alternativet NX, och låt andra anrop vänta en kort stund eller servera det tidigare värdet. Stale-while-revalidate och tidig uppdatering av heta nycklar minskar antalet hårda utgångar från början.

Berätta vad du behöver.

Något som ska byggas, personer som ska hittas eller en fråga som behöver ett svar. Under ett samtal på 30 minuter lyssnar vi och berättar ärligt hur vi kan hjälpa till, och vad som skulle krävas.

Boka ett samtal

30 minuter, på franska eller engelska. Kostnadsfritt.

Skriver du hellre? Skicka en kort förfrågan i stället.