Cachefremdes MusterCache-Aside pattern

Laden Sie Daten bei Bedarf aus einem Datenspeicher in einen Cache.Load data on demand into a cache from a data store. Dies kann die Leistung verbessern und trägt zudem dazu bei, die Konsistenz zwischen den Daten im Cache und den Daten im zugrunde liegenden Datenspeicher aufrechtzuerhalten.This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.

Kontext und ProblemContext and problem

Anwendungen verwenden einen Cache, um wiederholte Zugriffe auf Informationen in einem Datenspeicher zu verbessern.Applications use a cache to improve repeated access to information held in a data store. Allerdings kann nicht erwartet werden, dass zwischengespeicherte Daten immer vollständig konsistent mit den Daten im Datenspeicher sind.However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Anwendungen sollten eine Strategie implementieren, mit der sichergestellt wird, dass die Daten im Cache so aktuell wie möglich sind. Sie sollten jedoch auch Situationen erkennen und handhaben können, die auftreten, wenn die Daten im Cache veraltet sind.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.

LösungSolution

Viele kommerzielle Cachesysteme bieten Read-Through- und Write-Through-/Write-Behind-Vorgänge.Many commercial caching systems provide read-through and write-through/write-behind operations. In diesen Systemen ruft eine Anwendung Daten mithilfe von Verweisen auf den Cache ab.In these systems, an application retrieves data by referencing the cache. Wenn die Daten nicht im Cache enthalten sind, werden sie aus dem Datenspeicher abgerufen und dem Cache hinzugefügt.If the data isn't in the cache, it's retrieved from the data store and added to the cache. Änderungen an den im Cache gespeicherten Daten werden automatisch auch in den Datenspeicher zurückgeschrieben.Any modifications to data held in the cache are automatically written back to the data store as well.

Bei Caches, die diese Funktionalität nicht bereitstellen, ist es die Aufgabe der Anwendungen, die den Cache verwenden, die Daten zu verwalten.For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.

Eine Anwendung kann die Funktionalität eines Read-Through-Cache durch Implementieren einer Strategie mit dem cachefremden Muster emulieren.An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. Mit dieser Strategie werden Daten bei Bedarf in den Cache geladen.This strategy loads data into the cache on demand. Die Abbildung veranschaulicht die Verwendung des cachefremden Musters zum Speichern von Daten im Cache.The figure illustrates using the Cache-Aside pattern to store data in the cache.

Verwendung des cachefremden Musters zum Speichern von Daten im Cache

Aktualisiert eine Anwendung Informationen, kann sie die Write-Through-Strategie einsetzen, indem sie die Änderung am Datenspeicher vornimmt und das entsprechende Element im Cache ungültig macht.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.

Wenn das Element das nächste Mal benötigt wird, führt die Strategie mit dem cachefremden Muster dazu, dass die aktualisierten Daten aus dem Datenspeicher abgerufen und wieder zum Cache hinzugefügt werden.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.

Probleme und ÜberlegungenIssues and considerations

Beachten Sie die folgenden Punkte bei der Entscheidung, wie dieses Muster implementiert werden soll:Consider the following points when deciding how to implement this pattern:

Lebensdauer der zwischengespeicherten Daten.Lifetime of cached data. Viele Caches implementieren eine Ablaufrichtlinie, mit der die Daten ungültig gemacht und aus dem Cache entfernt werden, wenn für einen angegebenen Zeitraum nicht darauf zugegriffen wurde.Many caches implement an expiration policy that invalidates data and removes it from the cache if it's not accessed for a specified period. Damit das cachefremde Muster wirksam ist, stellen Sie sicher, dass die Ablaufrichtlinie zum Zugriffsmuster für Anwendungen passt, die die Daten verwenden.For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Legen Sie keinen zu kurzen Ablaufzeitraum fest. Dies könnte dazu führen, dass Anwendungen Daten kontinuierlich aus dem Datenspeicher abrufen und dem Cache hinzufügen.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. Legen Sie auch keinen zu langen Ablaufzeitraum fest, damit Sie keine veralteten Daten im Cache haben.Similarly, don't make the expiration period so long that the cached data is likely to become stale. Denken Sie daran, dass das Zwischenspeichern für relativ statische Daten oder für Daten, die häufig gelesen werden, am effektivsten ist.Remember that caching is most effective for relatively static data, or data that is read frequently.

Entfernen von Daten.Evicting data. Die meisten Caches haben im Vergleich mit dem Datenspeicher, aus dem die Daten stammen, eine beschränkte Größe, und sie müssen Daten ggf. entfernen.Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. In den meisten Caches werden dann die am längsten nicht mehr verwendeten Elemente entfernt, aber dies kann möglicherweise angepasst werden.Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Konfigurieren Sie die globale Ablaufeigenschaft und andere Eigenschaften des Cache sowie das Ablaufdatum der einzelnen Elemente im Cache, um sicherzustellen, dass der Cache kostengünstig ist.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. Es ist nicht immer angebracht, eine globale Entfernungsrichtlinie auf jedes Element im Cache anzuwenden.It isn't always appropriate to apply a global eviction policy to every item in the cache. Wenn es z.B. mit viel Aufwand verbunden ist, ein Element im Cache aus dem Datenspeicher abzurufen, kann es von Vorteil sein, dieses Element im Cache zu belassen und stattdessen häufiger verwendete, jedoch weniger aufwändige Elemente zu löschen.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.

Vorbereiten des Cache.Priming the cache. Viele Lösungen füllen den Cache vorab mit den Daten auf, die eine Anwendung wahrscheinlich als Teil der Verarbeitung beim Starten benötigt.Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. Das cachefremde Muster kann dennoch nützlich sein, wenn einige dieser Daten abgelaufen sind oder entfernt werden.The Cache-Aside pattern can still be useful if some of this data expires or is evicted.

Konsistenz.Consistency. Durch Implementieren des cachefremden Musters ist die Konsistenz zwischen dem Datenspeicher und dem Cache nicht garantiert.Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. Ein Element im Datenspeicher kann jedoch jederzeit von einem externen Prozess geändert werden, und diese Änderung wird möglicherweise erst im Cache wiedergegeben, wenn das Element das nächste Mal geladen wird.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 einem System, das Daten über Datenspeicher repliziert, kann dies ein ernsthaftes Problem werden, wenn die Synchronisierung häufig auftritt.In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.

Lokales (speicherinternes) Zwischenspeichern.Local (in-memory) caching. Ein Cache kann für eine Anwendungsinstanz lokal und im Speicher gespeichert sein.A cache could be local to an application instance and stored in-memory. Das cachefremde Muster kann in dieser Umgebung nützlich sein, wenn eine Anwendung wiederholt auf die gleichen Daten zugreift.Cache-aside can be useful in this environment if an application repeatedly accesses the same data. Allerdings ist ein lokaler Cache privat. Daher können verschiedene Anwendungsinstanzen jeweils über eine Kopie der gleichen zwischengespeicherten Daten verfügen.However, a local cache is private and so different application instances could each have a copy of the same cached data. Diese Daten können schnell zwischen Caches inkonsistent werden, sodass es möglicherweise erforderlich ist, dass Daten in einem privaten Cache ablaufen und häufiger aktualisiert werden.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 diesen Szenarien sollten Sie die Verwendung eines freigegebenen oder verteilten Mechanismus zum Zwischenspeichern prüfen.In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.

Verwendung dieses MustersWhen to use this pattern

Verwenden Sie dieses Muster in folgenden Fällen:Use this pattern when:

  • Ein Cache stellt keine nativen Read-Through- und Write-Through-Vorgänge bereit.A cache doesn't provide native read-through and write-through operations.
  • Der Ressourcenbedarf ist nicht vorhersehbar.Resource demand is unpredictable. Mit diesem Muster können Anwendungen Daten bei Bedarf laden.This pattern enables applications to load data on demand. Es werden im Voraus keine Annahmen darüber getroffen, welche Daten eine Anwendung benötigt.It makes no assumptions about which data an application will require in advance.

Dieses Muster ist in folgenden Fällen möglicherweise nicht geeignet:This pattern might not be suitable:

  • Wenn das zwischengespeicherte Dataset statisch ist.When the cached data set is static. Wenn die Daten in den verfügbaren Cachespeicher passen, bereiten Sie den Cache beim Start mit den Daten vor, und wenden Sie eine Richtlinie an, die verhindert, dass die Daten ablaufen.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.
  • Zum Zwischenspeichern von Sitzungszustandsinformationen in einer Webanwendung, die in einer Webfarm gehostet wird.For caching session state information in a web application hosted in a web farm. In dieser Umgebung sollten Sie vermeiden, dass Abhängigkeiten basierend auf der Client/Server-Affinität entstehen.In this environment, you should avoid introducing dependencies based on client-server affinity.

BeispielExample

In Microsoft Azure können Sie Azure Cache for Redis zum Erstellen eines verteilten Caches verwenden, der von mehreren Instanzen einer Anwendung gemeinsam genutzt werden kann.In Microsoft Azure you can use Azure Cache for Redis to create a distributed cache that can be shared by multiple instances of an application.

In diesen folgenden Codebeispielen wird der StackExchange.Redis-Client verwendet, eine für .NET geschriebene Redis-Clientbibliothek.This following code examples use the StackExchange.Redis client, which is a Redis client library written for .NET. Rufen Sie die statische Methode ConnectionMultiplexer.Connect auf, und übergeben Sie die Verbindungszeichenfolge, um eine Verbindung mit einer Azure Cache for Redis-Instanz herzustellen.To connect to an Azure Cache for Redis instance, call the static ConnectionMultiplexer.Connect method and pass in the connection string. Die Methode gibt ein ConnectionMultiplexer-Element zurück, das die Verbindung darstellt.The method returns a ConnectionMultiplexer that represents the connection. Ein Ansatz zur Freigabe einer ConnectionMultiplexer -Instanz in Ihrer Anwendung ist das Verwenden einer statischen Eigenschaft, die wie im folgenden Beispiel eine verbundene Instanz zurückgibt.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. Dieser Ansatz ist eine threadsichere Möglichkeit, um nur eine einzelne verbundene Instanz zu initialisieren.This approach provides a thread-safe way to initialize only a single connected instance.

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;

Die GetMyEntityAsync-Methode im folgenden Codebeispiel zeigt eine Implementierung des cachefremden Musters.The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern. Diese Methode ruft mit dem Read-Through-Ansatz ein Objekt aus dem Cache ab.This method retrieves an object from the cache using the read-through approach.

Ein Objekt wird mit einer ganzzahligen ID als Schlüssel identifiziert.An object is identified by using an integer ID as the key. Die GetMyEntityAsync-Methode versucht, ein Element mit diesem Schlüssel aus dem Cache abzurufen.The GetMyEntityAsync method tries to retrieve an item with this key from the cache. Wenn ein übereinstimmendes Element gefunden wird, wird es zurückgegeben.If a matching item is found, it's returned. Wenn im Cache keine Übereinstimmung vorhanden ist, ruft die GetMyEntityAsync-Methode das Objekt aus einem Datenspeicher ab, fügt es dem Cache hinzu und gibt es zurück.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. Der Code, der die Daten tatsächlich aus dem Datenspeicher liest, ist hier nicht dargestellt, da er vom Datenspeicher abhängt.The code that actually reads the data from the data store is not shown here, because it depends on the data store. Beachten Sie, dass für das zwischengespeicherte Element konfiguriert ist, dass es abläuft. Dadurch wird verhindert, dass es veraltet ist, wenn es an anderer Stelle aktualisiert wird.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 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;
}

Die Beispiele verwenden Azure Cache for Redis, um auf den Speicher zuzugreifen und Informationen aus dem Cache abzurufen.The examples use Azure Cache for Redis to access the store and retrieve information from the cache. Weitere Informationen finden Sie unter Verwenden von Azure Cache for Redis und Erstellen einer Web-App mit Azure Cache for Redis.For more information, see Using Azure Cache for Redis and How to create a Web App with Azure Cache for Redis.

Die unten gezeigte UpdateEntityAsync-Methode veranschaulicht, wie ein Objekt im Cache für ungültig erklärt wird, wenn der Wert von der Anwendung geändert wird.The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. Der Code aktualisiert den ursprünglichen Datenspeicher und entfernt dann das zwischengespeicherte Element aus dem Cache.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.
}

Hinweis

Die Reihenfolge der Schritte ist wichtig.The order of the steps is important. Aktualisieren Sie den Datenspeicher, bevor Sie das Element aus dem Cache entfernen.Update the data store before removing the item from the cache. Wenn Sie zuerst das zwischengespeicherte Element entfernen, entsteht ein kleines Zeitfenster, in dem ein Client das Element abrufen kann, bevor der Datenspeicher aktualisiert wird.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. Dies führt zu einem Cachefehler (da das Element aus dem Cache entfernt wurde). Dadurch wird die frühere Version des Elements aus dem Datenspeicher abgerufen und wieder im Cache hinzugefügt.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. Das Ergebnis sind veraltete Cachedaten.The result will be stale cache data.

Die folgenden Informationen sind unter Umständen auch relevant, wenn dieses Muster implementiert wird:The following information may be relevant when implementing this pattern:

  • Caching Guidance (Leitfaden zum Caching).Caching Guidance. Enthält weitere Informationen zum Zwischenspeichern von Daten in einer Cloudlösung und die Probleme, die Sie bedenken sollten, wenn Sie einen Cache implementieren.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.

  • Data Consistency Primer (Grundlagen der Datenkonsistenz).Data Consistency Primer. Cloudanwendungen verwenden in der Regel Daten, die auf Datenspeicher verteilt sind.Cloud applications typically use data that's spread across data stores. Das Verwalten und Erhalten der Datenkonsistenz in dieser Umgebung ist ein wichtiger Aspekt des Systems, insbesondere die Probleme mit Parallelität und Dienstverfügbarkeit, die auftreten können.Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. Dieser Artikel erläutert Probleme im Zusammenhang mit der Konsistenz verteilter Daten und fasst zusammen, wie eine Anwendung letztlich Konsistenz implementieren kann, um die Verfügbarkeit von Daten beizubehalten.This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.