Sperren mit Cache-Element-Versionierung (optimistisches Sperren)
Während Pessimistisches Sperren ist ein sehr hilfreicher Ansatz, es gibt jedoch eine Einschränkung bei der Verwendung: Ein Gegenstand kann erst verwendet werden, wenn mindestens eine Operation vollständig daran durchgeführt wurde. Das bedeutet, dass das Element gesperrt bleibt, bis eine Aufgabe vollständig für das Element ausgeführt wurde. Dies kann zu einem Thread-Aushungern führen, wenn ein Element über einen längeren Zeitraum gesperrt bleibt.
Note
Diese Funktion ist auch in verfügbar NCache Professional.
Hier kommt Optimistic Locking zum Einsatz NCache Verwendet die Versionierung von Cache-Elementen. CacheItemVersion
ist eine Eigenschaft, die jedem Cache-Element zugeordnet ist. Es handelt sich um einen numerischen Wert, der die Version des zwischengespeicherten Elements darstellt und sich bei jeder Aktualisierung eines Elements um eins erhöht. Mit dieser Eigenschaft können Sie nachverfolgen, ob an einem Element Änderungen vorgenommen wurden oder nicht. Wenn Sie ein Element aus dem Cache abrufen, rufen Sie auch seine aktuelle Version im Cache ab.
Für leseintensive Anwendungen wird optimistisches Sperren dem pessimistischen Sperren vorgezogen.
Wann sollte optimistisches Sperren verwendet werden?
Im vorherigen Beispiel hatten wir ein einzelnes Bankkonto, das von zwei Benutzern gleichzeitig genutzt wurde. Nehmen wir an, einer der Benutzer hat die Sperre für die Durchführung einer Einzahlungstransaktion auf dem Bankkonto erworben. Benutzer2 wartet darauf, dass Benutzer1 die Sperre freigibt, damit er die Auszahlungstransaktion durchführen kann. Bedenken Sie, dass Benutzer1 aufgrund von Netzwerkkonnektivitätsproblemen in einen instabilen Zustand übergeht, ohne dass die Sperre aufgehoben wird. Benutzer2 wartet weiterhin darauf, dass er die Sperre aufhebt, ohne Kenntnis von Verbindungsproblemen zu haben, sodass er in den Hungerzustand verfällt, bis der erste Benutzer die Sperre aufhebt.
Um diese Art von Problem zu vermeiden, ist Optimistic Locking eine nützliche Lösung. Wenn Benutzer1 mit dieser Art der Sperrung das Konto aktualisieren möchte, kann er das Konto aktualisieren, ohne es zu sperren, und die Artikelversion wird entsprechend aktualisiert. Wenn Benutzer2 nun die Daten aktualisieren möchte, erhält er die aktualisierte Version basierend auf der Artikelversion und stellt so sicher, dass keine Probleme mit der Datenintegrität auftreten. Wenn ein Benutzer die Daten mit der alten Artikelversion bearbeitet, schlägt der Vorgang fehl, da es sich um eine veraltete Artikelversion handelt.
CacheItemVersion
fügt der Entwicklung der Anwendung eine zusätzliche Dimension hinzu NCache. Optimistische Parallelität kann in Anwendungen erreicht werden durch NCache Artikelversionierung.
Wenn dem Cache ein Element hinzugefügt wird, wird die Version des Cache-Elements an den Cache-Client zurückgegeben. Dieser Wert gibt die Anzahl der Aktualisierungen an, die für bestimmte Daten durchgeführt wurden. Mit jedem Update erhöht sich der Wert der Artikelversion.
Voraussetzungen:
- Lernen Sie die Standardvoraussetzungen kennen, die für die Arbeit mit allen erforderlich sind NCache Weitere Informationen zu clientseitigen Funktionen finden Sie auf der angegebenen Seite Clientseitige API-Voraussetzungen.
- Einzelheiten zur API finden Sie unter: Speichern, ICache, CacheItem, CacheItemVersion, Enthält, Zu Zählen, GetIfNewer, Insert, Entfernen.
Rufen Sie den Artikel ab und aktualisieren Sie ihn mit der Artikelversion
An Speichern Die Operation gibt die zurück CacheItemVersion
. Wenn ein Element zum ersten Mal hinzugefügt wird, wird ein langer Wert zurückgegeben, der den Zeitstempel seiner Erstellung enthält. Diese Version wird um „1“ erhöht, wenn in Zukunft Operationen an diesem Schlüssel ausgeführt werden.
Optimistic Locking stellt sicher, dass der Benutzer immer die aktuellste Kopie des Elements aus dem Cache erhält. Wenn der Benutzer weiterhin Funktionen auf der veralteten Version ausführt, NCache löst eine Ausnahme aus, sodass der Benutzer das aktualisierte Element aus dem Cache erhält.
Im folgenden Beispiel wird ein Cache von mehreren Anwendungen verwendet. Der Cache enthält die Daten von Produkten. A CacheItem
wird dem Cache hinzugefügt. Beide Anwendungen rufen das Element mit der aktuellen Version ab, sagen wir Version. Anwendung1 ändert die Produktname Anschließend wird das Element erneut in den Cache eingefügt, wodurch die Elementversion des Elements auf die neue Version aktualisiert wird. Anwendung 2 verfügt noch über das Element mit der Version. Wenn Anwendung2 die vorrätigen Einheiten des Artikels aktualisiert und den Artikel erneut in den Cache einfügt, schlägt das Einfügen fehl. Anwendung2 muss die aktualisierte Version abrufen, um den Vorgang ausführen zu können CacheItem
.
Note
Mit beiden können Sie ein Element zum Cache hinzufügen Speichern or Insert Methoden.
- Das
Add
Die Methode fügt dem Cache ein neues Element hinzu und speichert die Elementversion zum ersten Mal. - Das
Insert
-Methode fügt ein Element in den Cache ein, wenn es noch nicht vorhanden ist, während es den Wert einer vorhandenen Zeit überschreibt und die Elementversion aktualisiert.
In den folgenden Codeabschnitten werden die von der Anwendung ausgeführten Vorgänge erläutert.
// Precondition: Cache is already connected
// An item is added in the cache with itemVersion
// Specify the key of the cacheItem
string key = "Product:1001";
// Initialize the cacheItemVersion
CacheItemVersion version = null;
// Get the cacheItem previously added in the cache with the version
CacheItem cacheItem = cache.GetCacheItem(key, ref version);
// If result is not null
if (cacheitem != null)
{
// CacheItem is retrieved successfully with the version
// If result is Product type
var prod = new Product();
prod = cacheItem.GetValue<Product>();
prod.UnitsInStock++;
// Create a new cacheItem with updated value
var updateItem = new CacheItem(prod);
//Set the itemversion. This version will be used to compare the
// item version of cached item
updateItem.Version = version;
cache.Insert(key, updateItem);
// If it matches, the insert will be successful, otherwise it will fail
}
else
{
// Item could not be retrieved due to outdated CacheItemVersion
}
Note
Um sicherzustellen, dass der Vorgang ausfallsicher ist, wird empfohlen, alle potenziellen Ausnahmen in Ihrer Anwendung zu behandeln, wie in erläutert Umgang mit Fehlern.
Rufen Sie das Element ab, wenn eine neuere Version im Cache vorhanden ist
Das GetIfNewer
Mit der Methode kann das vorhandene Element abgerufen werden, wenn eine neuere Version im Cache verfügbar ist. Durch die Angabe der aktuellen Version als Argument des Methodenaufrufs gibt der Cache das entsprechende Ergebnis zurück.
Wenn die angegebene Version kleiner ist als die im Cache, gibt die Methode nur dann ein neues Item else zurück null Wird zurückgegeben.
Das folgende Beispiel fügt mit dem Schlüssel ein Element zum Cache hinzu Product:1001
und Artikelversion und ruft sie dann ab, wenn eine neuere Version verfügbar ist GetIfNewer
Methode, die ein Element mithilfe der Cache-Elementversion abruft.
// Get updated product from database against given product ID
Product product = FetchProductByProductID(1001);
// Generate a unique key for this item
string key = $"Product:{product.ProductID}";
// Create a new CacheItem
var item = new CacheItem(product);
// Add CacheItem to cache with new itemversion
CacheItemVersion version = cache.Insert(key, item);
// Get object from cache
var result = cache.GetIfNewer<Product>(key, ref version);
// Check if updated item is available
if (result != null)
{
// An item with newer version is available
if (result is Product)
{
// Perform operations according to business logic
}
}
else
{
// No new itemVersion is available
}
Artikel mit Artikelversion entfernen
Ein Element kann mithilfe einer Überladung von aus dem Cache entfernt werden Entfernen, basierend auf der Elementversion. Wenn sich die Elementversion jedoch von der Version im Cache unterscheidet, erhalten Sie eine Ausnahme, die dies angibt.
Das folgende Beispiel zeigt, wie Sie ein Element aus dem Cache entfernen, indem Sie die Elementversion mithilfe von angeben Entfernen Methode.
Tipp
Sie können die Entfernung überwachen/verifizieren:
- "Cache Count"-Zähler ein NCache Überwachen or PerfMon-Zähler.
- Die richtigen
cache.Contains
nach Ablauf des Ablaufintervalls. - Die richtigen
cache.Count
vor und nach Angabe des Ablaufs.
// Get updated product from database against given product ID
Product product = FetchProductByProductID(1001);
// Cache key remains the same for this product
string key = $"Product:{product.ProductID}";
// Create a new CacheItem
var item = new CacheItem(product);
// Insert CacheItem to cache with new itemversion
CacheItemVersion version = cache.Insert(key, item);
// Remove the item from the cache using the itemVersion
cache.Remove(key, null, version);
Topologieweises Verhalten
- Für den Spiegel und den replizierten Cache
Im Spiegel Topologie: Wenn ein Element hinzugefügt oder aktualisiert wird, wird seine Version am aktiven Knoten generiert und dieselbe Version wird dann zusammen mit dem Element auf dem passiven Knoten repliziert, sodass die Elementversion dieselbe bleibt, wenn ein aktiver Knoten passiv wird.
Im Repliziert Topologie: Der Client ist mit einem Knoten verbunden und die Artikelversion wird an einem Knoten generiert, der den Aktualisierungs-/Hinzufügen-Vorgang des Clients empfängt. Anschließend wird dieselbe Artikelversion zusammen mit dem Artikel auf alle anderen Knoten repliziert, um die Datenkonsistenz zu gewährleisten.
- Für den partitionierten Cache und den Partition-Replica-Cache
Im Partitioniert Topologie: Die Artikelversion wird generiert und existiert auf demselben Knoten, der den Artikel enthält. Während der Statusübertragung wird die Version auch zusammen mit dem Artikel übertragen, falls der Artikel auf einen anderen Knoten verschoben wird.
Im Partitionsreplikat Topologie: Die Version wird auf dem aktiven Knoten generiert, der das Element enthält, und dieselbe Version wird dann zusammen mit dem Element zur Datenkonsistenz auf sein Replikat repliziert. Während der Statusübertragung wird die Version auch zusammen mit dem Element übertragen, falls das Element zu einem anderen verschoben wird Knoten.
- Client-Cache
Im Client-CacheAlle versionbezogenen Informationen werden im Cluster-Cache verwaltet, und wann immer eine versionbezogene API aufgerufen wird, erhält der Benutzer seine Version aus dem Cluster-Cache.
Weitere Informationen
NCache stellt eine Beispielanwendung für die Artikelsperre bereit GitHub.
Siehe auch
.NETZ: Alachisoft.NCache.Runtime.Caching Namespace.
Java: com.alachisoft.ncache.runtime.caching Namespace.
Node.js: Cache-Speicher Klasse.
Python: ncache.runtime.caching Klasse.