Verwenden von Memcached: Ist es empfehlenswert, den Cache beim Aktualisieren der Datenbank zu aktualisieren?

13

In dieser Frage geht es um Best Practices in der Architektur.

Unsere aktuelle Architektur

Ich habe eine PHP-Klasse, die auf MySQL zugreift, um Benutzerinformationen zu erhalten. Nennen wir es User. Userwird häufig zugegriffen, daher haben wir Caching-Ebenen implementiert, um die Last zu reduzieren.

Die erste Ebene wird als "Pro-Anfrage" -Cache bezeichnet. Nachdem die Daten von MySQL abgerufen wurden, speichern wir die Daten in einem privaten Eigentum von User. Alle nachfolgenden Anforderungen für die Daten geben die Eigenschaft zurück, anstatt die Daten erneut von MySQL anzufordern.

Da die Webanforderung auf Anfragebasis lebt und stirbt, verhindert dieser Cache, dass die Anwendung in einer einzelnen Anfrage mehr als einmal auf MySQL zugreift.

Unsere zweite Schicht ist Memcached. Wenn das Privateigentum leer ist, überprüfen wir Memcached zuerst auf die Daten. Wenn Memcached leer ist, fragen wir MySQL nach den Daten ab, aktualisieren Memcached und aktualisieren die Privateigenschaft von User.

Die Frage

Unsere Anwendung ist ein Spiel, und manchmal ist es unerlässlich, dass einige Daten so aktuell wie möglich sind. Innerhalb von etwa fünf Minuten kann eine Leseanforderung für die Benutzerdaten zehn- oder elfmal erfolgen. dann kann ein Update erfolgen. Nachfolgende Leseanforderungen müssen auf dem neuesten Stand sein, oder die Spielmechanik schlägt fehl.

Wir haben also einen Code implementiert, der ausgeführt wird, wenn eine Datenbankaktualisierung stattfindet. Dieser Code legt den Schlüssel in Memcached mit den aktualisierten Daten fest, sodass alle nachfolgenden Anforderungen an Memcached aktuell sind.

Ist das optimal? Gibt es Leistungsprobleme oder andere "Fallstricke", auf die wir achten sollten, wenn wir versuchen, eine Art "lebenden Cache" wie diesen zu verwalten?

Stephen
quelle
Was hat dies mit dem Löschen und erneuten Hinzufügen von Daten zu tun?
Mike Nakis
Der Fragentitel wurde geklärt.
Stephen
Warum nicht einfach die zwischengespeicherten Daten verfallen lassen? Das Aktualisieren bedeutet, dass Sie sicherstellen müssen, dass das Update beibehalten wird (wenn also neue Daten auf diese Weise aktualisiert werden müssen, müssen Sie das Update weiterhin ändern). Wenn der Cache abgelaufen ist, wird alles neu aus der Datenbank abgerufen - und für neue Updates müssen keine neuen Änderungen am Aktualisierungscode vorgenommen werden. Der Nachteil ist, dass die Datenbanklast möglicherweise höher ist.
Peter K.
@Peter Ja, auch darüber haben wir nachgedacht. Wenn keine anderen Probleme mit unserem aktuellen Ansatz auftauchen, bleiben wir dabei. Ansonsten können wir mit dem, was Sie beschrieben haben, gehen.
Stephen
1
@Stephen Der von Ihnen beschriebene Ansatz wird als "Write Through Cache" bezeichnet und ist ein recht gebräuchlicher Ansatz.
Sripathi Krishnan

Antworten:

10

Ich empfehle Ihnen, sich Ihr Nutzungsprofil und Ihre Anforderungen an den Cache anzusehen.

Ich kann keinen Grund erkennen, warum Sie veraltete Daten im Speicher belassen würden. Ich denke, Sie haben den richtigen Ansatz gewählt, dh: Aktualisieren Sie die DB.

In jedem Fall benötigen Sie einen Wrapper für Ihr DB-Update (was Sie getan haben). Ihr Code zum Aktualisieren des Benutzers in der Datenbank und im RAM sollte auch einen Push-Vorgang zum Speichern oder einen Ablauf im Speicher ausführen.

Zum Beispiel: Wenn Ihre Benutzer im Rahmen der Abmeldung normalerweise einmal pro Sitzung ein Update durchführen, ist es nicht sinnvoll, die Daten im Cache zu aktualisieren (z. B. Highscore-Gesamtsumme). Sie sollten sie sofort verfallen lassen.

WENN sie jedoch die Daten aktualisieren (z. B. den aktuellen Spielstatus) und dann 0,2 Sekunden später einen sofortigen PHP-Seitentreffer erhalten, der die Daten anfordert, möchten Sie, dass sie im Cache aktualisiert werden.

Jasonk
quelle
3

Ich würde nicht so vorgehen, wie Sie es beschrieben haben. Sie müssen sich nur entscheiden, ob Sie wirklich Daten benötigen, die auf dem neuesten Stand sind. Entscheiden Sie dann bei Bedarf, welche Teile der Daten jederzeit auf dem neuesten Stand sein müssen, und trennen Sie sie von Dingen, die in Ihrer Architektur zwischengespeichert werden können.

Beispielsweise möchten Sie wahrscheinlich die E-Mail-Adresse Ihres Benutzers aktualisieren, sobald sie geändert wird, damit Sie keine E-Mails an die falsche Adresse senden. Es ist jedoch unwahrscheinlich, dass das Geburtsdatum oder der Nachname des Benutzers vollständig sein muss Auf dem neuesten Stand, um ein anständiges Benutzererlebnis zu bieten. (NB Ich verwende kein Beispiel für eine Spielarchitektur, da ich nicht weiß, auf welche Art von Spiel ich es abzielen soll, und ich denke, dass dieses ziemlich einfach zu verstehen ist.)

Auf diese Weise erhalten Sie zwei eindeutige Datensätze: kurz- und langfristig zwischengespeicherte Daten. Sie können wahrscheinlich mit einer Cache-Dauer von etwa einer Minute für die kurzfristigen Daten davonkommen, um die Datenbank zu entlasten, aber die langfristigen Daten können für eine gleitende Dauer im Cache belassen werden, solange dies der Fall ist benutzt.

Dann müssen Sie sich um Updates kümmern. Ich würde zuerst einen DB-Trigger verwenden, um Elemente einfach aus dem Cache zu entfernen, sobald sie veraltet sind. Dadurch wird Ihre Business-Schicht gezwungen, beim nächsten Anfordern der Daten eine Cache-Aktualisierung auszulösen, wodurch Speicherplatz im Cache freigegeben wird, wenn die Daten nicht verwendet werden (z. B. wenn ein Benutzer seine E-Mail-Adresse ändert und sich dann sofort abmeldet). . Wenn dies zu Leistungsproblemen in der Benutzeroberfläche führt (z. B. zu viel Verzögerung beim Warten auf Cache-Aktualisierungen), können Sie einfach den Cache-Aufruf auslösen, sobald das Element aus dem Cache entfernt wurde. Ich würde auch versuchen, die DB-Lesezeiten für diesen kleinen Datensatz zu optimieren, um sicherzustellen, dass die Verzögerung beim Aktualisieren des Caches minimal ist (dies sollte einfacher sein, da Sie nur die Daten laden müssen, die Sie wirklich benötigen).

Was ich unter keinen Umständen tun würde, ist, eine zusätzliche Methode zum Füllen des Cache hinzuzufügen, da Sie dann den Aufruf (und API-Hooks usw.) an zwei Stellen verwalten müssen.

Bei Fallstricken müssen Sie vor allem aufpassen, wenn Sie direkt in den Cache schreiben, dass die Synchronisierung erfolgt. Wenn viele Threads versuchen zu lesen, während Sie Ihr unbeaufsichtigtes Update durchführen, können schwerwiegende ungültige Datenprobleme auftreten, die den Versuch zunichte machen, die Daten auf dem neuesten Stand zu halten.

Ed James
quelle