Een API met veel verkeer cache je door eerst te meten en dan een cache-aside-laag in Redis te zetten voor de traagste en meest gelezen endpoints, met expliciete TTL's, invalidatie bij schrijven en bescherming tegen cache stampedes. Gebruik Elasticsearch voor zoeken en gefilterde lijsten waar de primaire database slecht mee overweg kan, en cache nooit gebruikersspecifieke of strikt consistente data zonder een weloverwogen ontwerp.
Meet de P95-latency voordat je een cache toevoegt
Gemiddelden verbergen precies de requests waar gebruikers over klagen. Volg de P95- en P99-latency per endpoint, samen met het aantal requests, zodat je ziet welke routes zowel traag als druk gebruikt zijn.
Zoek daarna uit waar de tijd heen gaat. Een trace of een eenvoudige uitsplitsing van de tijd per request laat meestal zien of de kosten zitten in een trage query, herhaalde queries, een aanroep naar een externe API of serialisatie. Een response cachen waarvan het echte probleem een ontbrekende index is, verbergt dat probleem alleen tot de volgende cache miss.
- Leg P50, P95 en P99 per endpoint vast, niet alleen één globaal cijfer
- Rangschik endpoints op aantal requests maal latency om te zien waar caching het meest oplevert
- Controleer de verhouding tussen lezen en schrijven, want data die veel vaker wordt gelezen dan gewijzigd is de beste kandidaat
- Los ontbrekende indexen en N+1-queries op voordat je er een cache omheen bouwt
Gebruik cache-aside als standaardpatroon
Bij cache-aside kijkt de applicatie eerst in Redis. Bij een hit geeft ze de gecachete waarde terug. Bij een miss leest ze uit de database, schrijft ze het resultaat met een TTL naar Redis en geeft ze het terug.
Dit patroon houdt de database als bron van waarheid en faalt veilig. Is Redis traag of onbereikbaar, dan valt de applicatie terug op de database, met een korte timeout en een circuit breaker, zodat een haperende cache niet elk request vertraagt.
Ontwerp je keys bewust. Neem het type resource op, de identifier, de API-versie en elke parameter die de response verandert, zoals taal of pagina. Een voorspelbaar schema voor keys maakt gerichte invalidatie later mogelijk.
Stel TTL's in op hoe verouderd data mag zijn, en invalideer bij wijzigingen
Een TTL is een zakelijke beslissing in de vorm van een getal. Vraag je af hoe oud de data mag zijn voordat een gebruiker of een systeem verderop in de keten er last van heeft, en baseer de TTL op dat antwoord. Een live wedstrijdstand en een gearchiveerd artikel verdragen een heel verschillende mate van veroudering.
Vertrouw je alleen op verlopen, dan serveer je verouderde data tot de TTL om is. Voor data die je eigen applicatie wijzigt, verwijder of overschrijf je de key nadat de schrijfactie is gecommit, bij voorkeur via een event dat na de transactie wordt verstuurd, zodat de cache nooit data bevat die de database heeft teruggedraaid.
Voeg een kleine willekeurige jitter aan TTL's toe, zodat keys die tegelijk zijn geschreven niet allemaal op hetzelfde moment verlopen.
- Korte TTL van een paar seconden voor snel veranderende data waarbij een beetje veroudering acceptabel is
- Langere TTL plus invalidatie bij schrijven voor data die je zelf beheert en die zelden verandert
- Keys met een versie, waarbij het ophogen van een versienummer een hele groep keys in één keer ongeldig maakt
Bescherm de database tegen cache stampedes
Een stampede ontstaat als een populaire key verloopt en veel gelijktijdige requests tegelijk een miss krijgen, waarna ze allemaal dezelfde zware query naar de database sturen. Bij een API met veel verkeer kan dat de database overbelasten op precies het moment dat het verkeer piekt.
Combineer twee of meer van deze verdedigingen op je drukste keys.
- Request coalescing: één request bouwt de key opnieuw op onder een korte Redis-lock, gezet met NX en een vervaltijd, terwijl de andere even wachten of de vorige waarde serveren
- Stale-while-revalidate: bewaar een zachte vervaltijd in de waarde, blijf de verouderde kopie daarna nog serveren en ververs op de achtergrond
- Vroegtijdige probabilistische verversing: bouw een drukke key af en toe opnieuw op voordat hij verloopt, met een kans die groter wordt naarmate de vervaltijd nadert
- Voorverwarmen: vul bekende drukke keys vooraf, vóór een geplande verkeerspiek zoals een groot live-evenement
Gebruik Elasticsearch voor zoeken en lijsten, niet als algemene cache
Redis is het sterkst in opzoekingen op key: één object, een berekend fragment, een teller voor rate limiting. Elasticsearch is voor iets anders: full-text zoeken, facetfilters en gesorteerde lijsten die in een relationele database duur zijn om te berekenen.
Behandel de Elasticsearch-index als een leesmodel dat vanuit de primaire database wordt gevoed, via change events of een geplande synchronisatie, en accepteer dat hij eventually consistent is. Laat de database leidend zijn voor schrijfacties en voor alles wat exact moet kloppen.
Op het sportmediaplatform van NorthStar Network, dat 50M+ gebruikers per maand bedient, gaven onze engineers kritieke API's een nieuwe architectuur en ontwierpen ze de caching over Redis en Elasticsearch opnieuw, waardoor de P95-responstijden daalden.
Weet wat je niet moet cachen
De duurste fout bij caching is de data van de ene gebruiker aan een andere tonen. Controleer bij elk gecachet endpoint of de identiteit in de key zit, en test het vóór de release met twee verschillende accounts.
- Responses die afhangen van de identiteit of rechten van de aanroeper, tenzij de key de gebruiker of rol bevat
- Data die strikt consistent moet zijn, zoals saldi, voorraad bij het afrekenen of alles wat wordt gebruikt voor autorisatiebeslissingen
- Schrijf-endpoints, eenmalige tokens en alles met bijwerkingen
- Endpoints met weinig verkeer, waar een cache complexiteit en een nieuwe manier van falen toevoegt voor weinig winst
- Zeer grote payloads die veel kleinere, drukkere keys uit de cache verdringen
Maak de cache observeerbaar, anders kun je hem niet vertrouwen
Volg de hitratio per key-prefix, het geheugengebruik en de evictions van Redis, de latency van Redis-commando's en de databasebelasting, naast de P95 van de API op hetzelfde dashboard. Verschuift de P95, dan moet je binnen enkele minuten kunnen zien of de cache, de database of een upstream-service de oorzaak is.
Stel alerts in op een plotselinge daling van de hitratio, wat vaak betekent dat een deploy het formaat van een key heeft veranderd, en op stijgende evictions, wat betekent dat de cache te klein is voor zijn werkset.
We nemen werk aan API-performance aan als een afgebakend blok: meten, de cachinglaag opnieuw ontwerpen en dashboards en runbooks overdragen aan het team dat hem beheert.
De kern
- Meet de P95 per endpoint en los queryproblemen op voordat je een cache toevoegt.
- Cache-aside in Redis is de veiligste standaard, omdat de database de bron van waarheid blijft.
- Baseer TTL's op hoe verouderd de data mag zijn, en invalideer bij schrijven voor data die je zelf beheert.
- Bescherm drukke keys tegen stampedes met locking, stale-while-revalidate of voorverwarmen.
- Gebruik Elasticsearch als eventually consistent leesmodel voor zoeken en lijsten, niet als algemene cache.
Veelgestelde vragen
Redis of Elasticsearch: wat gebruik je om API-responses te cachen?
Gebruik Redis voor key-value-caching van objecten, berekende fragmenten en tellers, omdat opzoeken op key snel is en makkelijk te invalideren. Gebruik Elasticsearch als het dure deel zoeken, filteren of sorteren over veel records is, en behandel de index als een leesmodel in plaats van een cache.
Wat is een goede TTL voor API-responses?
Er is geen universele waarde. Baseer elke TTL op hoe verouderd die data mag zijn zonder dat een gebruiker er last van heeft, gebruik een paar seconden voor snel veranderende data en combineer langere TTL's met invalidatie bij schrijven. Voeg willekeurige jitter toe, zodat verwante keys niet tegelijk verlopen.
Hoe voorkom je een cache stampede in Redis?
Laat maar één request een verlopen key opnieuw opbouwen door een korte lock te nemen met SET en de optie NX, en laat andere requests even wachten of de vorige waarde serveren. Stale-while-revalidate en het vroegtijdig verversen van drukke keys verminderen het aantal harde verlopen al bij voorbaat.