NCache führt Eintragsprozessoren ein, damit wir eine Funktion (oder einen „Prozessor“) für eine Reihe von Caching-Einträgen auf der Serverseite ausführen können.
Um unsere Cache-Einträge zu aktualisieren, müssen wir normalerweise zweimal mit unserem Cache-Server „sprechen“. Einmal, um Einträge aus dem Cache abzurufen, und ein weiteres, um sie nach der Verarbeitung wieder zu aktualisieren. Aber mit Entry Processors aktualisieren wir unsere Cache-Einträge direkt auf dem Server und sparen uns diese Netzwerkreisen und unnötigen Ressourcenverbrauch.
NCache führt Eingangsprozessoren unabhängig von der verwendeten Caching-Topologie aus. Im Fall von partitionierten Topologien werden Eintragsprozessoren auf den Knoten ausgeführt, die unsere zu verarbeitenden Einträge enthalten.
Sobald wir einen Entry Processor aufrufen, verarbeitet er ein einzelnes Element oder einen Satz davon basierend auf der von uns definierten Logik. NCache lässt unseren Prozessor über den Cluster laufen. Innerhalb eines Eintragsprozessors können wir:
- Einen Cache-Eintrag zurückgeben, ohne ihn zu verarbeiten,
- Ändern Sie einen Eintrag und speichern Sie ihn im Cache oder
- Entfernen Sie einen Eintrag.
Wenn ein Eintrag gesperrt ist, bevor der Prozessor ausgeführt wird, können wir die Sperre ignorieren und auf den gesperrten Eintrag zugreifen, um ihn zu verarbeiten.
NCache Details NCache Eingabeprozessor Implementierung des Eintragsprozessors
Vergleich des Entry-Prozessors mit anderen Cache-Operationen
Eintragsprozessoren helfen uns, Cache oder Einträge direkt auf dem Server zu aktualisieren oder zu löschen, indem sie die Netzwerkfahrten zum Abrufen und Aktualisieren von Cache-Einträgen sparen.
Um Eingangsprozessoren in Aktion zu sehen, schreiben wir eine Konsolen-App, um einige Kunden in einen Cache zu laden. Lassen Sie uns den Namen, Prämienpunkte und das letzte Kaufdatum eines Kunden speichern. Und um unsere Kunden zum Kauf zu motivieren, verdoppeln wir die Prämienpunkte aller Kunden mit einem Einkauf in den letzten fünf Tagen. Lassen Sie uns dann dasselbe Szenario mit einem Eingangsprozessor und Bulk-Cache-Vorgängen neu erstellen, um den Unterschied in der Ausführungszeit zwischen diesen Ansätzen zu sehen.
Bevor wir mit unserer Beispielanwendung beginnen, sollten wir eine haben NCache Enterprise Edition-Instanz läuft. Entry Processors sind nur in der Enterprise Edition verfügbar.
1. Verwenden von Bulk-Cache-Vorgängen
NCache unterstützt Massenoperationen zum gleichzeitigen Abrufen und Aktualisieren von Cache-Einträgen in einem einzigen Aufruf. Mit Bulk-Vorgängen haben wir eine bessere Leistung, da wir die Anzahl der Netzwerkfahrten zu unserem Cache-Server reduzieren.
Um mehrere Cache-Einträge in großen Mengen abzurufen, benötigen wir die GetCacheItemBulk()
mit Schlüsselliste. Es gibt die gefundenen Elemente in einem Wörterbuch zurück. Und um Artikel in großen Mengen zu aktualisieren, benötigen wir die InsertBulk()
-Methode mit einem Wörterbuch der zu aktualisierenden Elemente.
Um unseren Vergleich zu starten, verwenden wir NCache GetCacheItemBulk()
und InsertBulk()
Methoden zum Abrufen und Aktualisieren von Cache-Einträgen in einer einzigen Anfrage.
Im Program.cs
Datei unserer Konsolen-App, lass uns so etwas schreiben,
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 34 35 |
using Alachisoft.NCache.Client; using RewardPoints; using RewardPoints.Shared; const string CacheName = "demoCache"; var customers = new List { new Customer(1, "Alice", DateTime.Today.AddDays(-1), 100), new Customer(2, "Bob", DateTime.Today.AddDays(-6), 5), new Customer(3, "Charlie", DateTime.Today.AddMonths(-1), 1), new Customer(4, "Daniel", DateTime.Today.AddDays(-3), 10), new Customer(5, "Earl", DateTime.Today, 20) }; var keys = customers.Select(c => c.ToCacheKey()); // Load customers into the cache ICache cache = CacheManager.GetCache(CacheName); PopulateCache(cache, customers); // Double customer points using NCache Bulk methods var retrievedItems = cache.GetCacheItemBulk(keys); var itemsToUpdate = new Dictionary<string, CacheItem>(); foreach (var item in retrievedItems) { var customer = item.Value.GetValue(); // Check if the customer has purchased anything in the last 5 days if (customer.LastPurchase >= DateTime.Today.AddDays(-5)) { var updated = customer with { Points = customer.Points * 2 }; itemsToUpdate.Add(updated.ToCacheKey(), updated.ToCacheItem()); } } cache.InsertBulk(itemsToUpdate); |
Zuerst haben wir einige Kunden in einen Cache geladen. Wir haben den standardmäßigen „demoCache“-Cache verwendet, der während der erstellt wurde NCache Installation. Als Nächstes haben wir unsere Kunden mithilfe von abgerufen GetCacheItemBulk()
Methode. Nachdem wir dann das letzte Kaufdatum jedes Kunden überprüft hatten, verdoppelten wir seine Punkte und legten alle aktualisierten Kunden zurück in den Cache.
Anstatt unsere Kunden einzeln zu aktualisieren, haben wir ein Wörterbuch verwendet, um die Kunden zu sammeln, die die Belohnung gewonnen haben. Dann benutzten wir die InsertBulk()
Methode mit dem Wörterbuch.
Mit der GetCacheItemBulk()
und InsertBulk()
Methoden haben wir unsere Netzwerkfahrten auf nur zwei reduziert. Ein Netzwerkaufruf, um alle Kunden abzurufen, und ein weiterer, um sie wieder im Cache zu speichern.
Weitere Einzelheiten zu diesen und anderen Bulk-Methoden finden Sie unter CRUD-Operationen: Ein Überblick.
NCache Details Massenoperationen Übersicht über Massenvorgänge
2. Verwendung eines Eingabeprozessors
Nachdem wir nun Bulk-Methoden verwendet haben, verdoppeln wir die Prämienpunkte unserer Kunden mit einem Entry Processor. Etwas wie das,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using Alachisoft.NCache.Client; using RewardPoints; using RewardPoints.Shared; const string CacheName = "demoCache"; var customers = new List { new Customer(1, "Alice", DateTime.Today.AddDays(-1), 100), new Customer(2, "Bob", DateTime.Today.AddDays(-6), 5), new Customer(3, "Charlie", DateTime.Today.AddMonths(-1), 1), new Customer(4, "Daniel", DateTime.Today.AddDays(-3), 10), new Customer(5, "Earl", DateTime.Today, 20) }; var keys = customers.Select(c => c.ToCacheKey()); // Load customers ICache cache = CacheManager.GetCache(CacheName); PopulateCache(cache, customers); // Double customer points using Entry Processor var processor = new DoublePointsProcessor(); cache.ExecutionService.Invoke(keys, processor); |
Beachten Sie, dass wir keine Methode verwenden mussten, um die Cache-Einträge zu aktualisieren. Wir haben nur einen Prozessor erstellt, eine Reihe von Schlüsseln übergeben und die aufgerufen Invoke()
Methode. Wir müssen die Kunden innerhalb des Eintragsprozessors selbst aktualisieren.
NCache Details NCache Eingabeprozessor Implementierung des Eintragsprozessors
Eingangsprozessoren konfigurieren
Um einen Eintragsprozessor zu schreiben, müssen wir eine Klasse erstellen, die erbt IEntryProcessor
und nutzt die [Serializable]
Attribut. Dies ist unser Eingangsprozessor,
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 |
using Alachisoft.NCache.Runtime.Processor; namespace RewardPoints.Shared; [Serializable] public class DoublePointsProcessor : IEntryProcessor { public bool IgnoreLock() => true; public object Process(IMutableEntry entry, params object[] arguments) { // Check if the cache entry is a customer and // if the customer has purchased something in the last 5 days if (entry.Key.StartsWith(nameof(Customer)) && entry.Value is Customer { LastPurchase: var lastPurchase } customer && lastPurchase >= DateTime.Today.AddDays(-5)) { // Update the customer's points var updatedCustomer = customer with { Points = customer.Points * 2 }; entry.Value = updatedCustomer; return updatedCustomer; } return false; } } |
Um einen Cache-Eintrag in einem Prozessor zu aktualisieren, müssen wir die überschreiben Value
Eigentum der entry
-Parameter mit dem aktualisierten Cache-Eintrag.
Wenn eine Client-Anwendung einen Eintrag sperrt, können wir den Eintragsprozessor mithilfe von ausführen IgnoreLock()
Methode. Es ignoriert die Sperre und greift auf den Eintrag zu, um ihn zu verarbeiten.
Bevor wir unseren neuen Prozessor verwenden, müssen wir die DLL mit unserem Prozessor und seinen Abhängigkeiten bereitstellen NCache. Wir können die Powershell verwenden Install-NCacheModule
Cmdlets bzw NCache Web-Manager. Anweisungen zum Bereitstellen unseres Eingangsprozessors mit dem Web Manager finden Sie unter Anbieter bereitstellen.
Lassen Sie uns beispielsweise unsere „demoCache“-Instanz stoppen und die Powershell ausführen Install-NCacheModule
Cmdlet,
NCache Details NCache Eingabeprozessor Implementierung des Eintragsprozessors
Wie gehen Entry Processors vor? mit Betriebsstörungen?
Sobald ein Eintragsprozessor läuft, gibt er eine Sammlung von Ergebnissen des Typs zurück IEntryProcessorResult
. Jedes Ergebnis enthält eine IsSuccessful
Flagge und a Value
mit dem Ergebnis unserer Modifikationen. Für unseren Sample-Entry-Prozessor, die Value
Eigenschaft enthält entweder false
, wenn der Kunde keinen kürzlichen Kauf getätigt hat, oder andernfalls ein aktualisierter Kunde.
Wenn eine Ausnahme ausgelöst wird, während der Eingangsprozessor läuft, wird die IsSuccessful
Flagge wird sein false
und für Exception
-Eigenschaft wird mit der ausgelösten Ausnahme gefüllt.
Um unseren Eingangsprozessor ausfallsicher zu machen, sollten wir alle möglichen Ausnahmen behandeln. Wir könnten zum Beispiel ein bekommen OperationFailedException
wenn es einen Verbindungsfehler gab. Außerdem könnten wir eine bekommen
EntryProcessorException
, in diesem Fall hat der Eintragsprozessor keine Cache-Einträge geändert.
So könnten wir die Eingabeergebnisse und mögliche Ausnahmemeldungen anzeigen,
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 34 35 36 37 38 39 40 |
using Alachisoft.NCache.Client; using RewardPoints; using RewardPoints.Shared; const string CacheName = "demoCache"; var customers = new List { new Customer(1, "Alice", DateTime.Today.AddDays(-1), 100), new Customer(2, "Bob", DateTime.Today.AddDays(-6), 5), new Customer(3, "Charlie", DateTime.Today.AddMonths(-1), 1), new Customer(4, "Daniel", DateTime.Today.AddDays(-3), 10), new Customer(5, "Earl", DateTime.Today, 20) }; var keys = customers.Select(c => c.ToCacheKey()); // Load customers ICache cache = CacheManager.GetCache(CacheName); PopulateCache(cache, customers); try { // Double customer points using Entry Processor var processor = new DoublePointsProcessor(); var processedEntries = cache.ExecutionService.Invoke(keys, processor); foreach (IEntryProcessorResult entryResult in processedEntries) { DisplayEntryResult(entryResult); } } catch (EntryProcessorException e) { Console.WriteLine($"Error running the processor: {e.Message}"); } catch (OperationFailedException e) { Console.WriteLine($"Error connecting to the cache server: {e.Message}"); } |
Lassen Sie uns nun unsere drei Alternativen nebeneinander ausführen. Ich lief sie auf meiner Maschine mit NCache lokal installiert und mit 20 zufälligen Kunden, die ich generiert habe Bogus. Und hier ist das Ergebnis,
Zusammenfassung
Definitiv war die Alternative mit einem Entry Processor die schnellste. Es war in 12 Millisekunden fertig, während das mit Bulk-Methoden in 72 Millisekunden fertig war. Bei Entry Processors haben wir eine Leistungssteigerung festgestellt, da wir alle übermäßigen Netzwerkreisen eingespart haben, indem wir die Punkte unserer Kunden direkt auf dem Server verdoppelt haben.
Das ist, was Entry Processors sind und wie sie funktionieren. Auch wenn wir keinen Benchmark geschrieben haben, um dies zu testen NCache Dieser Vergleich gibt uns eine Vorstellung davon, wie Entry Processors verwendet werden. Mit ihnen sparen wir uns manche Hin- und Rückfahrt NCache Server, indem unsere Cache-Einträge direkt in einem verarbeitet werden NCache Server. Wenn Sie das nächste Mal einige Ihrer Cache-Einträge aktualisieren müssen, versuchen Sie es mit Entry Processors.
Weitere Einzelheiten zur Funktionsweise von Entry Processors finden Sie unter Arbeiten des Eintragsprozessors im Cache.
Um dem Code zu folgen, den wir in diesem Beitrag geschrieben haben, check my NCache Demo-Repository auf GitHub.