Caching-Strategien - Amazon ElastiCache (RedisOSS)

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Caching-Strategien

Im folgenden Thema finden Sie Strategien zum Füllen und Verwalten Ihres Caches.

Welche Strategien Sie zum Auffüllen und Verwalten Ihres Cache implementieren müssen, hängt von den zwischengespeicherten Daten und den Zugriffsmustern auf diese Daten ab. Zum Beispiel möchten Sie wahrscheinlich nicht dieselbe Strategie für eine Top-10-Bestenliste auf einer Spieleseite und für trendige Nachrichten verwenden. Im Rest dieses Abschnitts besprechen wir gängige Cache-Wartungsstrategien und ihre Vor- und Nachteile.

Lazy Loading

Wie der Name schon sagt, ist Lazy Loading (“langsames Laden“) eine Caching-Strategie, die Daten nur bei Bedarf in den Cache lädt. Es funktioniert folgendermaßen.

Amazon ElastiCache ist ein speicherinterner Schlüsselwertspeicher, der sich zwischen Ihrer Anwendung und dem Datenspeicher (Datenbank) befindet, auf den sie zugreift. Immer wenn Ihre Anwendung Daten anfordert, sendet sie die Anfrage zuerst an den Cache. ElastiCache Wenn die Daten im Cache vorhanden und aktuell sind, werden die Daten an Ihre Anwendung ElastiCache zurückgegeben. Wenn die Daten nicht im Cache vorhanden sind oder abgelaufen sind, fordert Ihre Anwendung die Daten von Ihrem Datenspeicher an. Ihr Datenspeicher gibt die Daten dann an Ihre Anwendung zurück. Als nächstes schreibt Ihre Anwendung die vom Speicher empfangenen Daten in den Cache. Auf diese Weise können sie bei der nächsten Anforderung schneller abgerufen werden.

Ein Cache-Treffer tritt auf, wenn sich Daten im Cache befinden und nicht abgelaufen sind:

  1. Die Anwendung fordert Daten aus dem Cache an.

  2. Der Cache gibt die Daten an die Anwendung zurück.

Ein Cache-Fehltreffer tritt auf, wenn sich Daten nicht im Cache befinden oder abgelaufen sind:

  1. Die Anwendung fordert Daten vom Cache an.

  2. Der Cache enthält die angeforderten Daten nicht und gibt daher null zurück.

  3. Ihre Anwendung fordert die Daten an und erhält sie aus der Datenbank.

  4. Ihre Anwendung aktualisiert den Cache mit den neuen Daten.

Vor- und Nachteile von Lazy Loading

Die Vorteile von Lazy Loading sind:

  • Es werden nur die angeforderten Daten im Cache abgelegt.

    Da die meisten Daten nie angefordert werden, wird durch Lazy Loading vermieden, dass der Cache mit nicht angeforderten Daten gefüllt wird.

  • Knotenfehler sind für Ihre Anwendung nicht fatal.

    Wenn ein Knoten ausfällt und durch einen neuen, leeren Knoten ersetzt wird, funktioniert Ihre Anwendung weiterhin, allerdings mit erhöhter Latenz. Wenn Anforderungen an den neuen Knoten gestellt werden, führt jeder Cache-Fehltreffer zu einer Abfrage der Datenbank. Gleichzeitig wird die Datenkopie dem Cache hinzugefügt, so dass nachfolgende Anforderungen aus dem Cache abgerufen werden.

Die Nachteile von Lazy Loading sind:

  • Bei Cache-Fehlschlägen gibt es Verzögerungen. Jeder Cache-Fehltreffer führt zu drei Übertragungsvorgängen:

    1. Anfängliche Anforderung von Daten aus dem Cache

    2. Abfrage der Daten aus der Datenbank

    3. Schreiben der Daten in den Cache

    Diese Fehltreffer können zu einer merklichen Verzögerung beim Eingang der Daten in die Anwendung führen.

  • Veraltete Daten.

    Wenn Daten nur bei einem Cache-Fehltreffer in den Cache geschrieben werden, können Daten im Cache veraltet sein. Dieses Ergebnis tritt auf, weil der Cache nicht aktualisiert wird, wenn Daten in der Datenbank geändert werden. Um dieses Problem zu beheben, können Sie die Write-Through und Hinzufügen von TTL-Strategien anwenden.

Beispiel für Lazy Loading Pseudocode

Im Folgenden finden Sie ein Pseudocode-Beispiel für Lazy Loading-Logik.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record == null) customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record) return customer_record

In diesem Beispiel sieht der Anwendungscode, der die Daten abruft, wie folgt aus.

customer_record = get_customer(12345)

Write-Through

Die Write-Through-Strategie fügt dem Cache Daten hinzu oder aktualisiert Daten im Cache, wenn Daten in die Datenbank geschrieben werden.

Vor- und Nachteile von Write-Through

Die Vorteile von Write-Through sind:

  • Die Daten im Cache sind nie veraltet.

    Da die Daten im Cache jedes Mal aktualisiert werden, wenn sie in die Datenbank geschrieben werden, sind die Daten im Cache immer aktuell.

  • Schreibstrafe im Vergleich zu Lesestrafe.

    Jeder Schreibvorgang umfasst zwei Übertragungsvorgänge:

    1. Ein Schreibvorgang in den Cache

    2. Ein Schreibvorgang in die Datenbank

    Dadurch wird die Latenz des Prozesses erhöht. Endbenutzer tolerieren im Allgemeinen Latenz beim Aktualisieren von Daten eher als beim Abrufen. Aktualisierungen werden als arbeits- und zeitintensiver wahrgenommen.

Die Nachteile von Write-Through sind:

  • Fehlende Daten.

    Wenn Sie einen neuen Knoten hochfahren, sei es aufgrund eines Knotenfehlers oder einer horizontalen Skalierung, fehlen Daten. Diese Daten fehlen weiterhin, bis sie in der Datenbank hinzugefügt oder aktualisiert werden. Sie können dies minimieren, indem Sie Lazy Loading mit Write-Through implementieren.

  • Cache-Änderung.

    Die meisten Daten werden nie gelesen, was eine Verschwendung von Ressourcen darstellt. Durch Hinzufügen eines Time-to-Live-Werts (TTL) können Sie verschwendeten Speicherplatz minimieren.

Beispiel für Write-Through-Pseudocode

Das Folgende ist ein Pseudocode-Beispiel für Write-Through-Logik.

// ***************************************** // function that saves a customer's record. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record) return success

In diesem Beispiel sieht der Anwendungscode, der die Daten abruft, wie folgt aus.

save_customer(12345,{"address":"123 Main"})

Hinzufügen von TTL

Lazy Loading ermöglicht veraltete Daten, schlägt jedoch nicht wegen leeren Knoten fehl. Write-Through stellt sicher, dass die Daten immer frisch sind, kann aber bei leeren Knoten fehlschlagen und den Cache mit überflüssigen Daten füllen. Indem Sie jedem Schreibvorgang einen Time-to-Live-Wert (TTL) hinzufügen, können Sie die Vorteile jeder Strategie nutzen. Gleichzeitig können Sie das Überladen des Caches mit zusätzlichen Daten weitgehend vermeiden.

Time to Live (TTL) ist ein ganzzahliger Wert, der die Anzahl der Sekunden bis zum Ablauf des Schlüssels angibt. Redis OSS kann Sekunden oder Millisekunden für diesen Wert angeben. Wenn eine Anwendung versucht, einen abgelaufenen Schlüssel zu lesen, gilt der Schlüssel als nicht gefunden. Die Datenbank wird nach dem Schlüssel abgefragt und der Cache aktualisiert. Dieser Ansatz garantiert nicht, dass ein Wert nicht veraltet ist. Er verhindert jedoch, dass die Daten zu veraltet werden, und erfordert, dass Werte im Cache gelegentlich aus der Datenbank aktualisiert werden.

Beispiele für TTL Pseudocode

Das Folgende ist ein Pseudocode-Beispiel für Write-Through-Logik mit TTL.

// ***************************************** // function that saves a customer's record. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and future reads will have to query the database. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record, 300) return success

Das Folgende ist ein Pseudocode-Beispiel für Lazy-Loading-Logik mit TTL.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and subsequent reads will have to query the database. // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record != null) if (customer_record.TTL < 300) return customer_record // return the record and exit function // do this only if the record did not exist in the cache OR // the TTL was >= 300, i.e., the record in the cache had expired. customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record, 300) // update the cache return customer_record // return the newly retrieved record and exit function

In diesem Beispiel sieht der Anwendungscode, der die Daten abruft, wie folgt aus.

save_customer(12345,{"address":"123 Main"})
customer_record = get_customer(12345)

Verwandte Themen