Unternehmen entwickeln heute stark frequentierte ASP.NET-Webanwendungen, die Zehntausende gleichzeitiger Benutzer bedienen. Mehrere Clients haben Zugriff auf Cache-Daten in einer Clusterumgebung, in der Anwendungsserver in einer Umgebung mit Lastenausgleich bereitgestellt werden. Unter solchen parallelen Bedingungen versuchen oft mehrere Benutzer, auf dieselben Daten zuzugreifen und diese zu ändern, und lösen eine Race-Condition aus.
Eine Race-Condition liegt vor, wenn zwei oder mehr Benutzer versuchen, gleichzeitig auf dieselben gemeinsam genutzten Daten zuzugreifen und diese zu ändern, dies jedoch in der falschen Reihenfolge tun. Diese Situation führt zu einem hohen Risiko, die Datenintegrität und -konsistenz zu verlieren. Mit dem Aufkommen von skalierbaren In-Memory-Caching-Lösungen wie NCache Durch die Bereitstellung verteilter Sperrmechanismen können Unternehmen eine deutlich verbesserte Datenkonsistenz erreichen.
NCache Details Sperr- und Kontrolldokumente NCache Docs
Verteilte Sperrung für Datenkonsistenz
NCache bietet einen verteilten Mechanismus Sperrung in .NET, mit dem Sie bestimmte Cache-Elemente während gleichzeitiger Aktualisierungen sperren können. Um in solchen Fällen die Datenkonsistenz zu wahren, NCache fungiert als verteilter Sperrenmanager und stellt Ihnen zwei Arten von Sperren zur Verfügung:
Wir werden sie später im Blog im Detail besprechen. Betrachten Sie zunächst das folgende Szenario, um zu verstehen, wie es ohne einen verteilten Sperrdienst zu einer Verletzung der Datenintegrität kommt.
Zwei Benutzer greifen gleichzeitig mit einem Guthaben von 30,000 auf dasselbe Bankkonto zu. Ein Benutzer zieht 15,000 ab, während der andere Benutzer 5,000 einzahlt. Bei richtiger Ausführung sollte der Endsaldo 20,000 betragen. Im Gegenteil, wenn eine Race Condition auftritt, die nicht behoben wird, beträgt der Kontostand entweder 15,000 oder 35,000, wie Sie oben sehen können.
So tritt diese Rennbedingung auf:
- Zeitpunkt t1: Benutzer 1 ruft ein Bankkonto mit einem Saldo von 30,000 ab
- Zeitpunkt t2: Benutzer 2 ruft ein Bankkonto mit einem Saldo von 30,000 ab
- Zeitpunkt t3: Benutzer 1 hebt 15,000 ab und aktualisiert den Kontostand = 15,000
- Zeitpunkt t4: Benutzer 2 zahlt 5,000 ein und aktualisiert den Kontostand = 35,000
In beiden Fällen könnte ein Codeblock, der nicht für die Verwaltung von Threads geeignet ist, für die Bank katastrophale Folgen haben. Schauen wir uns in den folgenden Abschnitten an, wie das geht NCache stellt Sperrmechanismen bereit, um sicherzustellen, dass Ihre Anwendungslogik threadsicher ist.
NCache Details Pessimistisches Sperren Optimistisches Sperren
Optimistische Sperre (Artikelversionen)
In optimistisches Sperren, NCache verwendet Cache-Element-Versionierung. Auf der Serverseite ist jedem zwischengespeicherten Objekt eine Versionsnummer zugeordnet, die bei jeder Aktualisierung des Cache-Elements erhöht wird. NCache überprüft dann, ob Sie an der neuesten Version arbeiten. Wenn nicht, lehnt es Ihr Cache-Update ab. Auf diese Weise kann nur ein Benutzer aktualisieren, und andere Benutzeraktualisierungen schlagen fehl.
Mit beiden können Sie ein Element zum Cache hinzufügen Speichern or Insert Methoden.
- Add-Methode fügt ein neues Element im Cache hinzu und speichert die Elementversion zum ersten Mal.
- Die Insert-Methode überschreibt den Wert eines vorhandenen Elements und aktualisiert seine Elementversion.
Sehen Sie sich das folgende Codebeispiel an.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// Pre-condition: 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(); prod.UnitsInStock++; // Create a new cacheItem with updated value var updateItem = new CacheItem(prod); CacheItemVersion 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 } |
Im obigen Beispiel verwenden zwei verschiedene Anwendungen einen einzigen Cache, der die Daten von Produkten enthält. CacheItem wird dem Cache hinzugefügt. Nehmen wir an, beide Anwendungen rufen das Element mit der aktuellen Version ab Version. Anwendung1 ändert die Produktname und fügt dann das Element erneut in den Cache ein, der seine Elementversion auf aktualisiert neue Version. Anwendung2 hat den Artikel noch Version. Wenn Anwendung2 die Lagereinheiten des Artikels aktualisiert und den Artikel erneut in den Cache einfügt, schlägt das Einfügen des Artikels fehl. Anwendung2 muss daher die aktualisierte Version abrufen, um mit diesem Cache-Element zu arbeiten.
NCache Details Optimistisches Sperren Versionierung von Cache-Elementen
Wenn Sie jedoch ein vorhandenes Element abrufen möchten, für das möglicherweise eine neuere Version im Cache verfügbar ist, NCache stellt ein GetIfNewer Methode. Wenn Sie die aktuelle Version als Argument des Methodenaufrufs angeben, gibt der Cache ein entsprechendes Ergebnis zurück. Wenn die spezifische Version kleiner als die im Cache ist, gibt die Methode ein neues Element zurück, andernfalls gibt sie null zurück.
Schauen wir uns den folgenden Code an.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Get object from cache var result = cache.GetIfNewer(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 } |
Das obige Beispiel fügt dem Cache ein Element mit dem Schlüssel Product:1001 und der Elementversion hinzu. Wenn eine neuere Version des Artikels verfügbar ist, GetIfNewer -Methode ruft das Element mithilfe der Cache-Elementversion ab.
Mit optimistischer Verriegelung, NCache stellt sicher, dass jeder Schreibvorgang in den verteilten Cache mit der Version übereinstimmt, die jede Anwendung enthält. Bitte beachten Sie unsere offiziell NCache Dokumentation für ein ausführliches Codebeispiel.
NCache Details GetIfNewer CacheItemVersioning
Pessimistisches Sperren (exklusives Sperren)
Die andere Möglichkeit, die Datenkonsistenz sicherzustellen, besteht darin, eine exklusive Sperre für die zwischengespeicherten Daten zu erwerben. Dieser Mechanismus heißt Pessimistisches Sperren . Es sperrt das Element mit dem Sperr-Handle und hindert alle anderen Benutzer daran, Schreibvorgänge für dieses Cache-Element auszuführen. EIN LockHandle ist ein Handle, das jedem gesperrten Element im Cache zugeordnet ist, das von der Sperr-API zurückgegeben wird.
Das folgende Beispiel erstellt einen LockHandle und sperrt dann ein Element mit dem Schlüssel Product:1001 für eine Zeitspanne von 10 Sekunden, sodass das Element automatisch nach 10 Sekunden entsperrt wird.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Pre-Requisite: Cache is already connected // Item is already added in the cache // Specify the key of the item string key = $"Product:1001"; //Create a new LockHandle LockHandle lockHandle = null; // Specify time span of 10 seconds for which the item remains locked TimeSpan lockSpan = TimeSpan.FromSeconds(10); // Lock the item for a time span of 10 seconds bool lockAcquired = cache.Lock(key, lockSpan, out lockHandle); // Verify if the item is locked successfully if (lockAcquired == true) { // Item has been successfully locked } else { // Key does not exist // Item is already locked with a different LockHandle } |
Nachdem die Sperre beim Abrufen des Elements erfolgreich erworben wurde, kann die Anwendung nun sicher Operationen ausführen, da sie weiß, dass keine andere Anwendung dieses Element abrufen oder aktualisieren kann, solange Sie über diese Sperre verfügen. Wir rufen die Insert-API mit demselben Lock-Handle auf, um die Daten zu aktualisieren und die Sperre freizugeben. Dadurch werden die Daten in den Cache eingefügt und die Sperre aufgehoben, alles in einem Aufruf, sodass die zwischengespeicherten Daten für alle anderen Anwendungen verfügbar sind.
Denken Sie daran, dass Sie alle Sperren mit einem Timeout erwerben sollten. Wenn das Zeitlimit nicht angegeben ist, gilt standardmäßig: NCache sperrt den Artikel auf unbestimmte Zeit, Zeitspanne.Null. Es kann vorkommen, dass das Element für immer gesperrt bleibt, wenn die Anwendung abstürzt, ohne die Sperre aufzuheben. Für eine Problemumgehung könnten Sie gewaltsam loslassen es, aber diese Praxis ist nicht ratsam. Sperren Sie daher ein Element für die minimale TimeSpan, um Deadlocks oder Thread-Hunger zu vermeiden.
NCache Details Pessimistisches Sperren Verwenden des Sperrens mit zwischengespeicherten Daten Blog
Failover-Unterstützung beim verteilten Sperren
Da NCache ist ein In-Memory, verteilter Cache, es bietet außerdem vollständige Failover-Unterstützung, sodass es zu keinem Datenverlust kommt und es hochverfügbar ist. Im Falle eines Serverausfalls funktionieren Ihre Client-Anwendungen nahtlos weiter. In ähnlicher Weise werden auch Ihre Sperren im verteilten System von den replizierenden Knoten repliziert und verwaltet. Wenn ein Knoten ausfällt, während eine Ihrer Anwendungen eine Sperre erhält, wird sie automatisch mit den angegebenen Eigenschaften an einen neuen Knoten weitergegeben, z. B. Ablauf der Sperre.
Zusammenfassung
Welcher Verriegelungsmechanismus ist also der beste für Sie, optimistisch oder pessimistisch? Nun, es hängt von Ihrem Anwendungsfall ab und davon, was Sie erreichen möchten. Optimistic Locking bietet einen verbesserten Leistungsvorteil gegenüber Pessimistic Locking, insbesondere wenn Ihre Anwendungen leseintensiv sind. Aus Sicht der Datenkonsistenz ist Pessimistic Locking dagegen sicherer. Wählen Sie daher Ihren Verriegelungsmechanismus sorgfältig aus. Weitere Einzelheiten finden Sie unter Website . Falls Sie Fragen haben, kontaktieren Sie uns und lassen Sie sich von unseren Experten helfen!