Patroon Cache-AsideCache-Aside pattern

Gegevens op verzoek in een cache laden vanuit een gegevensarchief.Load data on demand into a cache from a data store. 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.This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.

Context en probleemContext and problem

Toepassingen maken gebruik van een cache om herhaalde toegang tot in een gegevensarchief opgeslagen gegevens te vereenvoudigen.Applications use a cache to improve repeated access to information held in a data store. Het is echter niet praktisch te verwachten dat gegevens in de cache altijd volledig consistent zijn met de gegevens in het gegevensarchief.However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Voor toepassingen dient er een strategie te worden geïmplementeerd waardoor de gegevens in de cache zo actueel mogelijk zijn, maar ook situaties kunnen detecteren en afhandelen die optreden als de gegevens in de cache verouderen.Applications should implement a strategy that helps to ensure that the data in the cache is as up-to-date as possible, but can also detect and handle situations that arise when the data in the cache has become stale.

OplossingSolution

Veel commerciële cachesystemen bieden read-through-bewerkingen en write-through-/schrijfbewerkingen.Many commercial caching systems provide read-through and write-through/write-behind operations. In deze systemen worden de gegevens opgehaald door naar de cache te verwijzen.In these systems, an application retrieves data by referencing the cache. Als de gegevens zich niet in de cache bevinden, worden ze opgehaald uit het gegevensarchief en aan de cache toegevoegd.If the data isn't in the cache, it's retrieved from the data store and added to the cache. Wijzigingen die zijn aangebracht aan gegevens in de cache, worden ook automatisch teruggeschreven naar het gegevensarchief.Any modifications to data held in the cache are automatically written back to the data store as well.

Voor caches die deze functionaliteit niet bieden, zijn de toepassingen die gebruikmaken van de cache verantwoordelijk voor het onderhouden van de cache.For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.

Een toepassing kan de functionaliteit van read-through caching emuleren door de cache-aside-strategie te implementeren.An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. Met deze strategie worden gegevens op verzoek in de cache geladen.This strategy loads data into the cache on demand. In de afbeelding wordt het gebruik van het cache-aside-patroon geïllustreerd voor het laden van gegevens in de cache.The figure illustrates using the Cache-Aside pattern to store data in the cache.

Het cache-aside-patroon gebruiken voor het laden van gegevens in de cache

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.If an application updates information, it can follow the write-through strategy by making the modification to the data store, and by invalidating the corresponding item in the cache.

Als het item vervolgens nodig is, dan worden bij gebruik van de cache-aside-strategie de bijgewerkte gegevens opgehaald uit het gegevensarchief en opnieuw aan de cache toegevoegd.When the item is next required, using the cache-aside strategy will cause the updated data to be retrieved from the data store and added back into the cache.

Problemen en overwegingenIssues and considerations

Beschouw de volgende punten als u besluit hoe u dit patroon wilt implementeren:Consider the following points when deciding how to implement this pattern:

Levensduur van gegevens in de cache.Lifetime of cached data. Voor veel caches is een verloopbeleid geïmplementeerd waardoor gegevens ongeldig worden gemaakt en uit de cache verwijderd als ze gedurende een bepaalde periode niet zijn opgevraagd.Many caches implement an expiration policy that invalidates data and removes it from the cache if it's not accessed for a specified period. 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.For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Maak de verloopperiode niet te kort, omdat dit ervoor kan zorgen dat toepassingen voortdurend gegevens uit het gegevensarchief ophalen en aan de cache toevoegen.Don't make the expiration period too short because this can cause applications to continually retrieve data from the data store and add it to the cache. Maak de verloopperiode ook niet zo lang dat de kans bestaat dat de gegevens verouderen.Similarly, don't make the expiration period so long that the cached data is likely to become stale. Gegevens opslaan in de cache is het meest effectief bij relatief statische gegevens of gegevens die regelmatig worden gelezen.Remember that caching is most effective for relatively static data, or data that is read frequently.

Gegevens onbeschikbaar maken.Evicting data. De meeste caches hebben een beperkte grootte in vergelijking tot het gegevensarchief waar de gegevens uit afkomstig zijn en de gegevens in de cache worden zo nodig onbeschikbaar gemaakt.Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. De meeste caches gebruiken een beleid waarbij de minst recent gebruikte items onbeschikbaar worden gemaakt. Dit kan echter worden aangepast.Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Configureer de globale verloopeigenschap en andere eigenschappen van de cache en de verloopeigenschap van elk item in de cache om ervoor te zorgen dat de cache rendabel is.Configure the global expiration property and other properties of the cache, and the expiration property of each cached item, to ensure that the cache is cost effective. Het is niet altijd het beste om een globaal beleid van onbeschikbaar maken toe te passen op elk item in de cache.It isn't always appropriate to apply a global eviction policy to every item in the cache. Als het bijvoorbeeld erg kostbaar is om een item in de cache uit het gegevensarchief te halen, kan het voordelig zijn het item in de cache te houden ten koste van items die vaker worden geopend maar die minder kosten.For example, if a cached item is very expensive to retrieve from the data store, it can be beneficial to keep this item in the cache at the expense of more frequently accessed but less costly items.

Cache voorbereiden.Priming the cache. In veel oplossingen wordt de cache vooraf gevuld met de gegevens die een toepassing waarschijnlijk nodig heeft als onderdeel van het startproces.Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. Het cache-aside-patroon kan ook hier nuttig zijn als een deel van die gegevens verloopt of onbeschikbaar is gemaakt.The Cache-Aside pattern can still be useful if some of this data expires or is evicted.

Consistentie.Consistency. Het implementeren van het cache-aside-patroon biedt geen garantie voor de consistentie tussen het gegevensarchief en de cache.Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. Een item in het gegevensarchief kan op elk moment door een extern proces worden gewijzigd. Deze wijziging wordt mogelijk pas van kracht in de cache totdat het volgende item wordt geladen.An item in the data store can be changed at any time by an external process, and this change might not be reflected in the cache until the next time the item is loaded. In een systeem waarbij gegevens in gegevensarchieven worden gerepliceerd, kan dit een ernstig probleem worden als er regelmatig wordt gesynchroniseerd.In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.

Opslaan in lokale cache (in-memory).Local (in-memory) caching. Een cache kan lokaal zijn voor een instantie van een toepassing en in-memory worden opgeslagen.A cache could be local to an application instance and stored in-memory. Cache-aside kan in een dergelijke omgeving handig zijn als een toepassing bij herhaling dezelfde gegevens ophaalt.Cache-aside can be useful in this environment if an application repeatedly accesses the same data. Een lokale cache is echter privé, dus verschillende toepassingsinstanties kunnen elk een kopie van dezelfde gegevens in de cache hebben.However, a local cache is private and so different application instances could each have a copy of the same cached data. 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.This data could quickly become inconsistent between caches, so it might be necessary to expire data held in a private cache and refresh it more frequently. In deze scenario's kunt u het gebruik van een gedeeld of gedistribueerd mechanisme voor opslaan in de cache overwegen.In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.

Wanneer dit patroon gebruikenWhen to use this pattern

Gebruik dit patroon wanneer:Use this pattern when:

  • Een cache biedt geen systeemeigen read-through- en write-through-bewerkingen.A cache doesn't provide native read-through and write-through operations.
  • De vraag naar resources is onvoorspelbaar.Resource demand is unpredictable. Dit patroon stelt toepassingen in staat op aanvraag gegevens te laden.This pattern enables applications to load data on demand. Het doet geen aannames over welke gegevens een toepassing van tevoren nodig heeft.It makes no assumptions about which data an application will require in advance.

Dit patroon kan ongeschikt zijn:This pattern might not be suitable:

  • Als de gegevensset in de cache statisch is.When the cached data set is static. Als de gegevens passen in de beschikbare cacheruimte, moet de cache bij het starten worden voorbereid met de gegevens en een beleid toegepast dat voorkomt dat de gegevens verlopen.If the data will fit into the available cache space, prime the cache with the data on startup and apply a policy that prevents the data from expiring.
  • Bij het opslaan van informatie over de sessiestatus in de cache in een webtoepassing die wordt gehost in een webfarm.For caching session state information in a web application hosted in a web farm. In deze omgeving dient u het introduceren van afhankelijkheden op basis van client-serveraffiniteit te vermijden.In this environment, you should avoid introducing dependencies based on client-server affinity.

VoorbeeldExample

In Microsoft Azure kunt u Azure Redis-Cache gebruiken om een gedistribueerde cache te maken die kan worden gedeeld door meerdere instanties van een toepassing.In Microsoft Azure you can use Azure Redis Cache to create a distributed cache that can be shared by multiple instances of an application.

Als u verbinding wilt maken met een Azure Redis Cache-instantie, roept u de statische Connect-methode aan en geeft u de verbindingsreeks door.To connect to an Azure Redis Cache instance, call the static Connect method and pass in the connection string. Met deze methode wordt een ConnectionMultiplexer geretourneerd die de verbinding representeert.The method returns a ConnectionMultiplexer that represents the connection. 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.One approach to sharing a ConnectionMultiplexer instance in your application is to have a static property that returns a connected instance, similar to the following example. Deze benadering biedt een thread-veilige manier om slechts één verbonden exemplaar te initialiseren.This approach provides a thread-safe way to initialize only a single connected instance.

private static ConnectionMultiplexer Connection;

// Redis Connection string info
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 op basis van Azure Redis Cache.The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern based on Azure Redis Cache. Deze methode wordt een object opgehaald uit de cache met behulp van de aanpak read-through.This method retrieves an object from the cache using the read-through approach.

Een object wordt geïdentificeerd aan de hand van een sleutel (een geheeltallige id).An object is identified by using an integer ID as the key. Met de GetMyEntityAsync-methode wordt met deze sleutel een item uit de cache opgehaald.The GetMyEntityAsync method tries to retrieve an item with this key from the cache. Als er een overeenkomend item wordt gevonden, wordt het geretourneerd.If a matching item is found, it's returned. Als er geen match is, wordt met de GetMyEntityAsync-methode het object uit een gegevensarchief gehaald, toegevoegd aan de cache en vervolgens geretourneerd.If there's no match in the cache, the GetMyEntityAsync method retrieves the object from a data store, adds it to the cache, and then returns it. De code die de gegevens in het gegevensarchief feitelijk leest, wordt hier niet getoond, omdat deze afhankelijk is van het gegevensarchief.The code that actually reads the data from the data store is not shown here, because it depends on the data store. Het item in de cache wordt geconfigureerd om te verlopen om te voorkomen dat het verouderd als het ergens anders wordt bijgewerkt.Note that the cached item is configured to expire to prevent it from becoming stale if it's updated elsewhere.

// 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's 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 het voorbeeld wordt de Azure Redis Cache-API gebruikt om het archief te openen en de gegevens uit de cache op te halen.The examples use the Azure Redis Cache API to access the store and retrieve information from the cache. Zie Using Microsoft Azure Redis Cache (Microsoft Azure Redis Cache gebruiken) en Een web-app maken met Redis-Cache voor meer informatieFor more information, see Using Microsoft Azure Redis Cache and How to create a Web App with Redis Cache

De hieronder getoonde UpdateEntityAsync-methode laat zien hoe een object in de cache ongeldig moet worden gemaakt als de waarde door de toepassing wordt gewijzigd.The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. Met de code wordt het oorspronkelijke gegevensarchief bijgewerkt en vervolgens wordt het item uit de cache verwijderd.The code updates the original data store and then removes the cached item from the cache.

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 van belang.The order of the steps is important. Werk het gegevensarchief bij voordat u het item uit de cache verwijdert.Update the data store before removing the item from the cache. Als u het cache-item eerst verwijdert, is er een korte periode gedurende welke een client het item kan ophalen voordat het gegevensarchief wordt bijgewerkt.If you remove the cached item first, there is a small window of time when a client might fetch the item before the data store is updated. Dit leidt tot een cachemisser (omdat het item uit de cache is verwijderd), waardoor de eerdere versie van het item uit het gegevensarchief moet worden gehaald en weer toegevoegd aan de cache.That will result in a cache miss (because the item was removed from the cache), causing the earlier version of the item to be fetched from the data store and added back into the cache. Dit resulteert in verouderde cache-gegevens.The result will be stale cache data.

De volgende informatie kan relevant zijn bij het implementeren van dit patroon:The following information may be relevant when implementing this pattern:

  • Richtlijnen voor caching.Caching Guidance. 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.Provides additional information on how you can cache data in a cloud solution, and the issues that you should consider when you implement a cache.

  • Inleiding over gegevensconsistentie.Data Consistency Primer. Cloudtoepassingen maken gewoonlijk gebruik van gegevens die over gegevensarchieven zijn verspreid.Cloud applications typically use data that's spread across data stores. Het beheren en handhaven van gegevensconsistentie in deze omgeving is een kritisch aspect van het systeem, met name omdat er problemen met gelijktijdigheid en beschikbaarheid op kunnen treden.Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. 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.This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.