Freigeben über


Cachefremdes Muster

Azure Managed Redis

Dieses Muster lädt Daten bei Bedarf in einen Cache aus einem Datenspeicher. Verwenden Sie dieses Muster, um die Leistung zu verbessern und die Konsistenz zwischen Daten in einem Cache und Daten in einem zugrunde liegenden Datenspeicher aufrechtzuerhalten.

Kontext und Problem

Anwendungen verwenden einen Cache, um die Leistung für wiederholten Zugriff auf Informationen in einem Datenspeicher zu verbessern. Zwischengespeicherte Daten können jedoch nicht immer mit dem Datenspeicher konsistent bleiben. Anwendungen sollten eine Strategie implementieren, mit der die Daten im Cache so up-to-date wie möglich beibehalten werden. Die Strategie sollte auch erkennen, wann zwischengespeicherte Daten veraltet werden und entsprechend behandelt werden.

Lösung

Viele kommerzielle Caching-Systeme bieten Read-Through-, Write-Through- oder Write-Behind-Vorgänge. In diesen Systemen ruft eine Anwendung Daten mithilfe von Verweisen auf den Cache ab. Wenn sich die Daten nicht im Cache befinden, ruft die Anwendung sie aus dem Datenspeicher ab und fügt sie dem Cache hinzu. Das System schreibt automatisch alle Änderungen, die an zwischengespeicherten Daten vorgenommen wurden, in den Datenspeicher zurück.

Für Caches, die diese Funktionalität nicht bereitstellen, müssen die Anwendungen, die den Cache verwenden, die Daten verwalten.

Eine Anwendung kann die Funktionalität des Read-Through-Cachings emulieren, indem sie das Cache-Aside-Muster implementiert. Mit dieser Strategie werden Daten bei Bedarf in den Cache geladen. Im folgenden Diagramm wird das Cache-Aside Muster zum Speichern von Daten im Cache verwendet.

Diagramm, das die Verwendung des Cache-Aside Musters zum Lesen und Speichern von Daten im Cache zeigt.

  1. Die Anwendung bestimmt, ob sich derzeit ein Element im Cache befindet, indem versucht wird, aus dem Cache zu lesen.

  2. Wenn sich das Element nicht im Cache befindet, auch als Cachefehler bezeichnet, ruft die Anwendung das Element aus dem Datenspeicher ab.

  3. Die Anwendung fügt das Element dem Cache hinzu und gibt es dann an den Aufrufer zurück.

Wenn eine Anwendung Informationen aktualisiert, kann sie der Write-Through-Strategie folgen, indem sie die Änderung am Datenspeicher vornimmt und das entsprechende Element im Cache ungültig macht.

Wenn das Element erneut benötigt wird, ruft das Cache-Aside Muster die aktualisierten Daten aus dem Datenspeicher ab und fügt es dem Cache hinzu.

Probleme und Überlegungen

Berücksichtigen Sie die folgenden Punkte, wenn Sie sich für die Implementierung dieses Musters entscheiden:

  • Lebensdauer von zwischengespeicherten Daten: Viele Caches verwenden eine Ablaufrichtlinie, um Daten ungültig zu machen und aus dem Cache zu entfernen, wenn für einen festgelegten Zeitraum nicht darauf zugegriffen wird. Stellen Sie sicher, dass die Ablaufrichtlinie dem Zugriffsmuster der Anwendungen entspricht, die die Daten verwenden, um das Cache-Aside-Verfahren effektiv zu gestalten. Machen Sie den Ablaufzeitraum nicht zu kurz, da der vorzeitige Ablauf dazu führen kann, dass Anwendungen kontinuierlich Daten aus dem Datenspeicher abrufen und dem Cache hinzufügen. Setzen Sie den Ablaufzeitraum nicht so lang an, dass die zwischengespeicherten Daten veralten. Das Zwischenspeichern eignet sich am besten für relativ statische Daten oder Daten, die von Anwendungen häufig gelesen werden.

  • Daten entfernen: Die meisten Caches haben eine begrenzte Größe im Vergleich zu dem Datenspeicher, aus dem die Daten stammen. Wenn der Cache seine Größenbeschränkung überschreitet, werden Daten entfernt. Die meisten Caches übernehmen eine am wenigsten kürzlich verwendete Richtlinie zur Auswahl von Elementen zur Entfernung, aber einige erlauben Anpassungen.

  • Konfiguration: Sie können das Cacheverhalten global oder pro zwischengespeichertes Element konfigurieren. Eine einzelne globale Entfernungsrichtlinie könnte möglicherweise nicht für alle Elemente geeignet sein. Wenn ein Element teuer zum Abrufen ist, konfigurieren Sie das Cacheelement einzeln. In dieser Situation ist es sinnvoll, das Element im Cache zu behalten, auch wenn er weniger häufig aufgerufen wird als billigere Elemente.

  • Vorprimieren des Caches: Viele Lösungen füllen den Cache vorab mit Daten auf, die eine Anwendung als Teil der Startverarbeitung wahrscheinlich benötigt. Das Cache-Aside Pattern bleibt nützlich, wenn einige dieser Daten veralten oder entfernt werden.

  • Konsistenz: Das Cache-Aside Muster garantiert keine Konsistenz zwischen dem Datenspeicher und dem Cache. Ein externer Prozess kann z. B. jederzeit ein Element im Datenspeicher ändern. Diese Änderung wird erst im Cache angezeigt, wenn das Element erneut geladen wird. In einem System, das Daten in allen Datenspeichern repliziert, kann die häufige Synchronisierung die Konsistenz erschweren.

  • Lokales Zwischenspeichern: Ein Cache kann in einer Anwendungsinstanz lokal sein und im Arbeitsspeicher gespeichert werden. Zwischenspeichern funktioniert in dieser Umgebung gut, wenn eine Anwendung wiederholt auf dieselben Daten zugreift. Ein lokaler Cache ist jedoch privat, sodass unterschiedliche Anwendungsinstanzen jeweils über eine Kopie derselben zwischengespeicherten Daten verfügen können. Diese Daten können schnell zwischen Caches inkonsistent werden, daher müssen Sie möglicherweise Daten in einem privaten Cache ablaufen und sie häufiger aktualisieren. In diesen Szenarien sollten Sie einen gemeinsam genutzten oder verteilten Cachemechanismus verwenden.

  • Semantische Zwischenspeicherung: Einige Workloads können davon profitieren, den Cacheabruf basierend auf der semantischen Bedeutung statt exakten Schlüsseln durchzuführen. Dieser Ansatz reduziert die Anzahl der Anforderungen und Token, die an Sprachmodelle gesendet werden. Verwenden Sie die semantische Zwischenspeicherung nur, wenn die Daten die semantische Äquivalenz unterstützen, keine nicht verwandten Antworten zurückgeben und keine privaten und vertraulichen Daten enthalten. Beispielsweise ist "Was ist mein jährliches Nettoeinkommen?" semantisch ähnlich wie "Was ist mein jährliches Nettoeinkommen?" Aber wenn verschiedene Nutzer diese Fragen formulieren, sollten die Antworten unterschiedlich ausfallen. Sie sollten diese vertraulichen Daten auch nicht in Den Cache einschließen.

Wann man dieses Muster verwendet

Verwenden Sie dieses Muster in folgenden Fällen:

  • Ein Cache stellt keine nativen Read-Through- und Write-Through-Vorgänge bereit.

  • Der Ressourcenbedarf ist nicht vorhersehbar. Mit diesem Muster können Anwendungen Daten bei Bedarf laden. Es wird nicht davon ausgegangen, welche Daten eine Anwendung im Voraus benötigt.

Dieses Muster ist möglicherweise nicht geeignet, wenn:

  • Die Daten sind vertraulich oder sicherheitsbezogen. Das Speichern von Daten in einem Cache ist möglicherweise unangemessen, insbesondere wenn mehrere Anwendungen oder Benutzer den Cache freigeben. Rufen Sie diesen Datentyp immer aus der primären Quelle ab.

  • Der zwischengespeicherte Datensatz ist statisch. Wenn die Daten in den verfügbaren Cachebereich passen, primieren Sie den Cache mit den Daten beim Start, und wenden Sie eine Richtlinie an, die verhindert, dass die Daten ablaufen.

  • Die meisten Anfragen führen zu keinem Cache-Treffer. In diesem Fall kann der Aufwand für die Überprüfung des Caches und das Laden von Daten darin die Vorteile des Zwischenspeicherns überwiegen.

  • Sie zwischenspeichern Sitzungsstatusinformationen in einer Webanwendung, die in einer Webfarm gehostet wird. Vermeiden Sie in dieser Umgebung die Einführung von Abhängigkeiten basierend auf der Clientserveraffinität.

Arbeitslastgestaltung

Bewerten Sie, wie das Cache-Aside-Pattern im Entwurf einer Workload eingesetzt wird, um die in den Azure Well-Architected Framework-Säulen besprochenen Ziele und Prinzipien zu erfüllen. Die folgende Tabelle enthält Anleitungen dazu, wie dieses Muster die Ziele jeder Säule unterstützt.

Säule So unterstützt dieses Muster die Säulenziele
Zuverlässigkeitsentwurfsentscheidungen helfen Ihrer Arbeitsauslastung, ausfallsicher zu werden und sicherzustellen, dass sie nach auftreten eines Fehlers wieder in einen voll funktionsfähigen Zustand versetzt wird. Das Zwischenspeichern repliziert Daten. Auf begrenzte Weise kann die Verfügbarkeit häufig aufgerufener Daten beibehalten werden, wenn der Ursprungsdatenspeicher vorübergehend nicht verfügbar ist. Wenn der Cache nicht funktioniert, kann die Workload auf den Ursprungsdatenspeicher zurückgreifen.

- RE:05 Redundanz
Performance Efficiency hilft Ihrem Workload durch Optimierungen bei Skalierung, Daten und Code, die Anforderungen effizient zu erfüllen . Das Zwischenspeichern verbessert die Leistung für schwer lesbare Daten, die sich selten ändern und einige Veraltetkeit tolerieren.

- PE:08 Datenleistung
- PE:12 Kontinuierliche Leistungsoptimierung

Wenn dieses Muster Kompromisse innerhalb einer Säule einführt, sollten Sie sie gegen die Ziele der anderen Säulen berücksichtigen.

Beispiel

Erwägen Sie die Verwendung von Azure Managed Redis zum Erstellen eines verteilten Caches, den mehrere Anwendungsinstanzen freigeben können.

Im folgenden Beispiel wird der StackExchange.Redis-Client verwendet, bei dem es sich um eine Redis-Clientbibliothek handelt, die für .NET geschrieben wurde. Rufen Sie die statische ConnectionMultiplexer.Connect Methode auf, und übergeben Sie die Verbindungszeichenfolge, um eine Verbindung mit einer Azure Managed Redis-Instanz herzustellen. Die Methode gibt ein ConnectionMultiplexer-Element zurück, das die Verbindung darstellt.

Eine Möglichkeit, eine ConnectionMultiplexer Instanz in Ihrer Anwendung freizugeben, besteht darin, eine statische Eigenschaft zu haben, die eine verbundene Instanz zurückgibt, ähnlich wie im folgenden Beispiel. Dieser Ansatz ist eine threadsichere Möglichkeit, um nur eine einzelne verbundene Instanz zu initialisieren.

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 Beispiel zeigt eine Implementierung des Cache-Aside Musters. Diese Methode ruft ein Objekt aus dem Cache mithilfe des Read-Through-Ansatzes ab.

Die Methode identifiziert ein Objekt mithilfe einer ganzzahligen ID als Schlüssel. Es versucht, ein Element mithilfe dieses Schlüssels aus dem Cache abzurufen. Wenn der Cache ein übereinstimmende Element enthält, wird das Element zurückgegeben. Wenn der Cache keine Übereinstimmung enthält, ruft die GetMyEntityAsync Methode das Objekt aus einem Datenspeicher ab, fügt es dem Cache hinzu und gibt es dann zurück. In diesem Beispiel wird der Code weggelassen, der die Daten aus dem Datenspeicher liest, da diese Logik vom Datenspeicher abhängt. Das zwischengespeicherte Element ist so konfiguriert, dass es abläuft, um zu verhindern, dass es veraltet wird, wenn ein anderer Dienst aktualisiert oder verarbeitet wird.

// 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;
}

Hinweis

In den Beispielen wird Azure Managed Redis verwendet, um auf den Speicher zuzugreifen und Informationen aus dem Cache abzurufen. Weitere Informationen finden Sie unter Erstellen einer Azure Managed Redis-Instanz und Verwenden von Azure Managed Redis in .NET Core.

Die folgende UpdateEntityAsync Methode veranschaulicht, wie ein Objekt im Cache ungültig wird, wenn die Anwendung den Wert ändert. Der Code aktualisiert den ursprünglichen Datenspeicher und entfernt dann das zwischengespeicherte Element aus dem 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. Aktualisieren Sie den Datenspeicher, bevor Sie das Element aus dem Cache entfernen. Wenn Sie das zwischengespeicherte Element zuerst entfernen, gibt es ein kleines Zeitfenster, in dem ein Client das Element abrufen kann, bevor der Datenspeicher aktualisiert wird. In diesem Fall führt der Abruf zu einem Cachefehler, da sich das Element nicht im Cache befindet. Der Cachefehler bewirkt, dass die Anwendung das veraltete Element aus dem Datenspeicher abruft und dem Cache wieder hinzu fügt. Diese Sequenz führt zu veralteten Daten im Cache.

Nächste Schritte

  • Datenkonsistenzprimierung: Dieser Primer beschreibt Probleme mit der Konsistenz über verteilte Daten. Außerdem wird zusammengefasst, wie eine Anwendung letztendliche Konsistenz implementieren kann, um die Verfügbarkeit von Daten aufrechtzuerhalten. Cloudanwendungen speichern Daten in der Regel in mehreren Datenspeichern und Speicherorten. Sie müssen die Datenkonsistenz in dieser Umgebung effizient verwalten und aufrechterhalten, insbesondere aufgrund von Konkurrenz- und Verfügbarkeitsproblemen, die auftreten können.

  • Verwenden Sie Azure Managed Redis als semantischen Cache: In diesem Lernprogramm erfahren Sie, wie Sie die semantische Zwischenspeicherung mithilfe von Azure Managed Redis implementieren.

  • Zuverlässiges Web App-Muster: Dieses Muster wendet das Cache-Aside Muster auf Webanwendungen in der Cloud an.

  • Zwischenspeicherungsleitfaden: Dieser Leitfaden enthält weitere Informationen zum Zwischenspeichern von Daten in einer Cloudlösung und Zu berücksichtigende Probleme bei der Implementierung eines Caches.