Patroon Cache-Aside
Gegevens op verzoek in een cache laden vanuit een gegevensarchief. Dit kan de prestaties verbeteren en bevordert tevens het handhaven van de consistentie tussen gegevens die zijn opgeslagen in de cache en de gegevens in het onderliggende gegevensarchief.
Context en probleem
Toepassingen maken gebruik van een cache om herhaalde toegang tot in een gegevensarchief opgeslagen gegevens te vereenvoudigen. Het is echter onrealistisch om te verwachten dat gegevens in de cache altijd consistent zijn met het gegevensarchief. Toepassingen moeten een strategie implementeren die ervoor zorgt dat de gegevens in de cache zo up-to-date mogelijk zijn. De strategie moet ook kunnen detecteren wanneer gegevens in de cache verouderd zijn en deze op de juiste manier verwerken.
Oplossing
Veel commerciële cachesystemen bieden read-through-bewerkingen en write-through-/schrijfbewerkingen. In deze systemen worden de gegevens opgehaald door naar de cache te verwijzen. Als de gegevens zich niet in de cache bevinden, haalt de toepassing deze op uit het gegevensarchief en voegt deze toe aan de cache. Wijzigingen die zijn aangebracht aan gegevens in de cache, worden ook automatisch teruggeschreven naar het gegevensarchief.
Voor caches die deze functionaliteit niet bieden, zijn de toepassingen die gebruikmaken van de cache verantwoordelijk voor het onderhouden van de cache.
Een toepassing kan de functionaliteit van read-through caching emuleren door de cache-aside-strategie te implementeren. Met deze strategie worden gegevens op verzoek in de cache geladen. In de afbeelding wordt het gebruik van het cache-aside-patroon geïllustreerd voor het laden van gegevens in de cache.
- De toepassing bepaalt of het item zich momenteel in de cache bevindt door te proberen te lezen uit de cache.
- Als het item niet actueel is in de cache (een cachemisser), haalt de toepassing het item op uit het gegevensarchief.
- De toepassing voegt het item toe aan de cache en retourneert het vervolgens aan de aanroeper.
Als informatie wordt bijgewerkt, kan de write-through-strategie worden gevolgd door de wijziging aan het gegevensarchief aan te brengen en door het overeenkomstige item in de cache ongeldig te maken.
Wanneer het item opnieuw nodig is, haalt de strategie cache-aside de bijgewerkte gegevens op uit het gegevensarchief en voegt het toe aan de cache.
Problemen en overwegingen
Beschouw de volgende punten als u besluit hoe u dit patroon wilt implementeren:
Levensduur van gegevens in de cache. Veel caches gebruiken een verloopbeleid om gegevens ongeldig te maken en te verwijderen uit de cache als deze gedurende een bepaalde periode niet worden geopend. Wil de cache-aside-strategie effectief zijn, dan dient u ervoor te zorgen dat het verloopbeleid overeenkomt met het toegangspatroon voor toepassingen die van de gegevens gebruikmaken. Maak de verloopperiode niet te kort omdat voortijdige vervaldatum ertoe kan leiden dat toepassingen voortdurend gegevens ophalen uit het gegevensarchief en deze toevoegen aan de cache. Maak de verloopperiode ook niet zo lang dat de kans bestaat dat de gegevens verouderen. Gegevens opslaan in de cache is het meest effectief bij relatief statische gegevens of gegevens die regelmatig worden gelezen.
Gegevens onbeschikbaar maken. De meeste caches hebben een beperkte grootte vergeleken met het gegevensarchief waar de gegevens vandaan komen. Als de cache de maximale grootte overschrijdt, worden gegevens verwijderd. De meeste caches gebruiken een minst recent gebruikt beleid voor het selecteren van items die moeten worden verwijderd, maar het kan wel aanpasbaar zijn.
Configuratie. Cacheconfiguratie kan zowel globaal als per item in de cache worden ingesteld. Eén globaal verwijderingsbeleid is mogelijk niet geschikt voor alle items. Een configuratie voor een cache-item kan geschikt zijn als een item duur is om op te halen. In deze situatie is het zinvol om het item in de cache te houden, zelfs als het minder vaak wordt geopend dan goedkopere items.
Cache voorbereiden. In veel oplossingen wordt de cache vooraf gevuld met de gegevens die een toepassing waarschijnlijk nodig heeft als onderdeel van het startproces. Het cache-aside-patroon kan ook hier nuttig zijn als een deel van die gegevens verloopt of onbeschikbaar is gemaakt.
Consistentie. Het implementeren van het cache-aside-patroon biedt geen garantie voor de consistentie tussen het gegevensarchief en de cache. Een extern proces kan bijvoorbeeld op elk gewenst moment een item in het gegevensarchief wijzigen. Deze wijziging wordt pas in de cache weergegeven als het item opnieuw wordt geladen. In een systeem dat gegevens repliceert in gegevensarchieven, kan consistentie lastig zijn als er vaak synchronisatie plaatsvindt.
Opslaan in lokale cache (in-memory). Een cache kan lokaal zijn voor een instantie van een toepassing en in-memory worden opgeslagen. Cache-aside kan in een dergelijke omgeving handig zijn als een toepassing bij herhaling dezelfde gegevens ophaalt. Een lokale cache is echter privé, dus verschillende toepassingsinstanties kunnen elk een kopie van dezelfde gegevens in de cache hebben. De gegevens in de verschillende caches kunnen snel inconsistent worden ten opzichte van elkaar, dus het kan noodzakelijk zijn om gegevens in een privécache te laten verlopen en ze vaker te vernieuwen. In deze scenario's kunt u het gebruik van een gedeeld of gedistribueerd mechanisme voor opslaan in de cache overwegen.
Semantische caching. Sommige workloads kunnen profiteren van het ophalen van caches op basis van semantische betekenis in plaats van exacte sleutels. Dit vermindert het aantal aanvragen en tokens dat naar taalmodellen wordt verzonden. Zorg ervoor dat de gegevens die in de cache worden opgeslagen, profiteren van semantische gelijkwaardigheid en lopen geen risico om niet-gerelateerde antwoorden te retourneren of privé- en gevoelige gegevens te bevatten. Bijvoorbeeld: "Wat is mijn jaarlijkse salaris thuis nemen?" is semantisch vergelijkbaar met 'Wat is mijn jaarlijkse take home pay?', maar als dit wordt gevraagd door twee verschillende gebruikers, zodat het antwoord niet hetzelfde zou moeten zijn, en u wilt deze gevoelige gegevens ook opnemen in uw cache.
Wanneer dit patroon gebruiken
Gebruik dit patroon wanneer:
- Een cache biedt geen systeemeigen read-through- en write-through-bewerkingen.
- De vraag naar resources is onvoorspelbaar. Dit patroon stelt toepassingen in staat op aanvraag gegevens te laden. Er worden geen veronderstellingen over welke gegevens een toepassing vooraf vereist.
Dit patroon kan ongeschikt zijn:
- Als de gegevens gevoelige of beveiligingsgerelateerde gegevens zijn. Het kan ongepast zijn om deze op te slaan in een cache, met name als de cache wordt gedeeld tussen meerdere toepassingen of gebruikers. Ga altijd naar de primaire bron van de gegevens.
- Als de gegevensset in de cache statisch is. Als de gegevens in de beschikbare cacheruimte passen, moet u de cache primeren met de gegevens bij het opstarten en een beleid toepassen dat voorkomt dat de gegevens verlopen.
- Wanneer de meeste aanvragen geen cache raken. In dit geval kan de overhead van het controleren van de cache en het laden van gegevens in de cache opwegen tegen de voordelen van caching.
- Bij het opslaan van sessiestatusgegevens in een webtoepassing die wordt gehost in een webfarm. In deze omgeving dient u het introduceren van afhankelijkheden op basis van client-serveraffiniteit te vermijden.
Workloadontwerp
Een architect moet evalueren hoe het Cache-Aside patroon kan worden gebruikt in een ontwerp om de doelstellingen en principes te verhelpen die worden behandeld in de pijlers van het Azure Well-Architected Framework. Voorbeeld:
| Pijler | Hoe dit patroon ondersteuning biedt voor pijlerdoelen |
|---|---|
| Beslissingen over betrouwbaarheidsontwerp helpen uw workload bestand te worden tegen storingen en ervoor te zorgen dat deze herstelt naar een volledig functionerende status nadat er een fout is opgetreden. | Caching maakt gegevensreplicatie en kan op beperkte manieren worden gebruikt om de beschikbaarheid van veelgebruikte gegevens te behouden als het oorspronkelijke gegevensarchief tijdelijk niet beschikbaar is. Als er een storing in de cache is, kan de werkbelasting ook terugvallen op het oorspronkelijke gegevensarchief. - RE:05 Redundantie |
| Prestatie-efficiëntie helpt uw workload efficiënt te voldoen aan de vereisten door optimalisaties in schalen, gegevens, code. | Het gebruik van een cache-cab verbetert de prestaties voor leesintensieve gegevens die niet vaak worden gewijzigd en die bepaalde veroudering kunnen verdragen. - PE:08 Gegevensprestaties - PE:12 Continue prestatieoptimalisatie |
Net als bij elke ontwerpbeslissing moet u rekening houden met eventuele compromissen ten opzichte van de doelstellingen van de andere pijlers die met dit patroon kunnen worden geïntroduceerd.
Opmerking
Overweeg het gebruik van Azure Managed Redis om een gedistribueerde cache te maken die meerdere toepassingsexemplaren kunnen delen.
In dit volgende codevoorbeeld wordt de StackExchange.Redis-client gebruikt. Dit is een Redis-clientbibliotheek die is geschreven voor .NET. Als u verbinding wilt maken met een Azure Managed Redis-exemplaar, roept u de statische ConnectionMultiplexer.Connect methode aan en geeft u de verbindingsreeks door. Met deze methode wordt een ConnectionMultiplexer geretourneerd die de verbinding representeert. U kunt een exemplaar van ConnectionMultiplexer in uw toepassing delen door een statische eigenschap in te stellen die een verbonden exemplaar retourneert, zoals in het volgende voorbeeld. Deze benadering biedt een thread-veilige manier om slechts één verbonden exemplaar te initialiseren.
private static ConnectionMultiplexer Connection;
// Redis connection string information
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
string cacheConnection = ConfigurationManager.AppSettings["CacheConnection"].ToString();
return ConnectionMultiplexer.Connect(cacheConnection);
});
public static ConnectionMultiplexer Connection => lazyConnection.Value;
De GetMyEntityAsync methode in het volgende codevoorbeeld toont een implementatie van het cache-aside-patroon. Met deze methode wordt een object opgehaald uit de cache met behulp van de leesmethode.
Een object wordt geïdentificeerd aan de hand van een sleutel (een geheeltallige id). Met de GetMyEntityAsync-methode wordt met deze sleutel een item uit de cache opgehaald. Als er een overeenkomend item wordt gevonden, retourneert de cache het. Als er geen match is, wordt met de GetMyEntityAsync-methode het object uit een gegevensarchief gehaald, toegevoegd aan de cache en vervolgens geretourneerd. De code die de gegevens uit het gegevensarchief leest, wordt hier niet weergegeven, omdat deze afhankelijk is van het gegevensarchief. Het item in de cache is zo geconfigureerd dat het verloopt om te voorkomen dat het verouderd wordt als een andere service of proces het bijwerkt.
// Set five minute expiration as a default
private const double DefaultExpirationTimeInMinutes = 5.0;
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = $"MyEntity:{id}";
var cache = Connection.GetDatabase();
// Try to get the entity from the cache.
var json = await cache.StringGetAsync(key).ConfigureAwait(false);
var value = string.IsNullOrWhiteSpace(json)
? default(MyEntity)
: JsonConvert.DeserializeObject<MyEntity>(json);
if (value == null) // Cache miss
{
// If there's a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
value = ...;
// Avoid caching a null value.
if (value != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it is to have stale data.
await cache.StringSetAsync(key, JsonConvert.SerializeObject(value)).ConfigureAwait(false);
await cache.KeyExpireAsync(key, TimeSpan.FromMinutes(DefaultExpirationTimeInMinutes)).ConfigureAwait(false);
}
}
return value;
}
In de voorbeelden wordt Azure Managed Redis gebruikt om toegang te krijgen tot het archief en informatie op te halen uit de cache. Zie Een door Azure beheerde Redis maken en Azure Redis gebruiken in .NET Core voor meer informatie.
De UpdateEntityAsync onderstaande methode laat zien hoe u een object in de cache ongeldig maakt wanneer de toepassing de waarde wijzigt. Met de code wordt het oorspronkelijke gegevensarchief bijgewerkt en vervolgens wordt het item uit de cache verwijderd.
public async Task UpdateEntityAsync(MyEntity entity)
{
// Update the object in the original data store.
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false);
// Invalidate the current cache object.
var cache = Connection.GetDatabase();
var id = entity.Id;
var key = $"MyEntity:{id}"; // The key for the cached object.
await cache.KeyDeleteAsync(key).ConfigureAwait(false); // Delete this key from the cache.
}
Notitie
De volgorde van de stappen is belangrijk. Werk het gegevensarchief bij voordat u het item uit de cache verwijdert. Als u het item in de cache eerst verwijdert, is er een klein tijdvenster waarin een client het item kan ophalen voordat het gegevensarchief wordt bijgewerkt. In dit geval resulteert het ophalen in een cachemissing (omdat het item uit de cache is verwijderd). De cachemisser zorgt ervoor dat de eerdere versie van het item wordt opgehaald uit het gegevensarchief en weer wordt toegevoegd aan de cache. Het resultaat is verlopen cachegegevens.
Verwante resources
De volgende informatie kan relevant zijn bij het implementeren van dit patroon:
Betrouwbaar web-app-patroon laat zien hoe u het cache-aside-patroon kunt toepassen op webtoepassingen die in de cloud worden samengevoegd.
Richtlijnen voor caching. Biedt aanvullende informatie over hoe u in geval van een cloudoplossing gegevens in de cache kunt plaatsen, en over de problemen waar u rekening mee dient te houden als u een cache implementeert.
Inleiding over gegevensconsistentie. Cloudtoepassingen slaan doorgaans gegevens op in meerdere gegevensarchieven en locaties. Het beheren en onderhouden van gegevensconsistentie in deze omgeving is een essentieel aspect van het systeem, met name de gelijktijdigheid en beschikbaarheidsproblemen die zich kunnen voordoen. In de inleiding worden problemen beschreven met consistentie van gedistribueerde gegevens en er wordt een samenvatting gegeven van hoe een toepassing uiteindelijk consistentie kan implementeren om de beschikbaarheid van gegevens te handhaven.
Gebruik Azure Managed Redis als een semantische cache. In deze zelfstudie leert u hoe u semantische caching implementeert met behulp van Azure Managed Redis.