NCache introduce procesadores de entrada para permitirnos ejecutar una función (o "procesador") contra un conjunto de entradas de almacenamiento en caché en el lado del servidor.
Por lo general, para actualizar nuestras entradas de caché, tenemos que "hablar" con nuestro servidor de caché dos veces. Una vez para recuperar entradas del caché y otra para actualizarlas después de procesarlas. Pero, con los Entry Processors, actualizamos nuestras entradas de caché directamente en el servidor, ahorrando estos viajes de red y el consumo innecesario de recursos.
NCache ejecuta procesadores de entrada independientemente de la topología de almacenamiento en caché que se utilice. En el caso de topologías particionadas, los procesadores de entrada se ejecutan en los nodos que contienen nuestras entradas para procesar.
Una vez que invocamos un procesador de entrada, procesa un solo elemento o un conjunto de ellos en función de la lógica que definimos. NCache ejecuta nuestro procesador en todo el clúster. Dentro de un procesador de entrada, podemos:
- Devuelve una entrada de caché sin procesarla,
- Modificar una entrada y guardarla en la memoria caché o,
- Eliminar una entrada.
Si una entrada está bloqueada antes de ejecutar el procesador, podemos ignorar el bloqueo y acceder a la entrada bloqueada para procesarla.
NCache Detalles NCache Procesador de entrada Implementación del procesador de entrada
Comparación del procesador de entrada con otras operaciones de caché
Los procesadores de entrada nos ayudan a actualizar o purgar el caché o las entradas directamente en el servidor al ahorrar los viajes de la red para obtener y actualizar las entradas del caché.
Para ver los procesadores de entrada en acción, escribamos una aplicación de consola para cargar algunos clientes en un caché. Almacenemos el nombre, los puntos de recompensa y la última fecha de compra de un cliente. Y para motivar a nuestros clientes a comprar, dupliquemos los puntos de recompensa de todos los clientes con una compra en los últimos cinco días. Luego, recreemos el mismo escenario usando un procesador de entrada y operaciones de caché masiva para ver la diferencia en el tiempo de ejecución entre estos enfoques.
Antes de comenzar nuestra aplicación de muestra, debemos tener una NCache Enterprise instancia de edición en funcionamiento. Los procesadores de entrada solo están disponibles en la edición Enterprise.
1. Uso de operaciones de caché masiva
NCache admite operaciones masivas para recuperar y actualizar entradas de caché simultáneamente en una sola llamada. Con las operaciones masivas, tenemos un mejor rendimiento ya que reducimos la cantidad de viajes de red a nuestro servidor de caché.
Para recuperar múltiples entradas de caché de forma masiva, necesitamos el GetCacheItemBulk()
con una lista de llaves. Devuelve los elementos encontrados en un diccionario. Y, para actualizar elementos de forma masiva, necesitamos la InsertBulk()
método con un diccionario de elementos para actualizar.
Para comenzar nuestra comparación, usemos NCache GetCacheItemBulk()
y InsertBulk()
métodos para recuperar y actualizar entradas de caché en una sola solicitud.
En Program.cs
archivo de nuestra aplicación Consola, escribamos algo como esto,
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); |
Primero, cargamos algunos clientes en un caché. Usamos el caché predeterminado "demoCache" creado durante el NCache instalación. A continuación, recuperamos a nuestros clientes utilizando el GetCacheItemBulk()
método. Luego, después de verificar la última fecha de compra de cada cliente, duplicamos sus puntos y volvimos a colocar todos los clientes actualizados en el caché.
En lugar de actualizar a nuestros clientes individualmente, usamos un diccionario para acumular los clientes que ganaron la recompensa. Luego usamos el InsertBulk()
método con el diccionario.
Con la GetCacheItemBulk()
y InsertBulk()
métodos, redujimos nuestros viajes de red a solo dos. Una llamada de red para recuperar todos los clientes y otra para guardarlos nuevamente en el caché.
Para obtener más detalles sobre estos y otros métodos masivos, consulte Operaciones CRUD: una descripción general.
NCache Detalles Operaciones masivas Resumen de operaciones masivas
2. Uso de un procesador de entrada
Ahora que hemos usado métodos masivos, dupliquemos los puntos de recompensa de nuestros clientes usando un procesador de entrada. Algo como esto,
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); |
Tenga en cuenta que no tuvimos que usar ningún método para actualizar las entradas de caché. Solo creamos un procesador, pasamos un conjunto de claves y llamamos al Invoke()
método. Tenemos que actualizar los clientes dentro del propio procesador de entrada.
NCache Detalles NCache Procesador de entrada Implementación del procesador de entrada
Configuración de procesadores de entrada
Para escribir un procesador de entrada, necesitamos crear una clase que herede de IEntryProcessor
y usa el [Serializable]
atributo. Este es nuestro procesador de entrada,
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; } } |
Para actualizar una entrada de caché en un procesador, necesitamos sobrescribir el Value
propiedad de la entry
parámetro con la entrada de caché actualizada.
Si una aplicación cliente está bloqueando una entrada, podemos ejecutar el Procesador de entrada sobre ella usando el IgnoreLock()
método. Ignorará el bloqueo y accederá a la entrada para procesarla.
Antes de usar nuestro nuevo procesador, debemos implementar la DLL con nuestro procesador y sus dependencias para NCache. Podemos usar el Powershell Install-NCacheModule
cmdlet o NCache Administrador web. Para obtener instrucciones sobre cómo implementar nuestro procesador de entrada mediante Web Manager, consulte Implementar proveedores.
Por ejemplo, detengamos nuestra instancia "demoCache" y ejecutemos Powershell Install-NCacheModule
cmdlet,
NCache Detalles NCache Procesador de entrada Implementación del procesador de entrada
¿Cómo funcionan los procesadores de entrada? ¿Fracasos de operación?
Una vez que se ejecuta un procesador de entrada, devuelve una colección de resultados de tipo IEntryProcessorResult
. Cada resultado contiene un IsSuccessful
bandera y una Value
con el resultado de nuestras modificaciones. Para nuestro procesador de entrada de muestra, el Value
la propiedad contendrá false
, si el cliente no tuvo ninguna compra reciente, o un cliente actualizado, en caso contrario.
Si se lanza una excepción mientras se ejecuta el procesador de entrada, el IsSuccessful
la bandera será false
y del Exception
La propiedad se completará con la excepción lanzada.
Para hacer que nuestro procesador de entrada sea a prueba de fallas, debemos manejar cualquier posible excepción. Por ejemplo, podríamos obtener un OperationFailedException
si hubo algún fallo de conexión. Además, podríamos obtener un
EntryProcessorException
, en este caso, el procesador de entrada no modificó ninguna entrada de caché.
Así es como podríamos mostrar los resultados de la entrada y los posibles mensajes de excepción,
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}"); } |
Ahora, analicemos nuestras tres alternativas una al lado de la otra. Los ejecuté en mi máquina con NCache instalado localmente y usando 20 clientes aleatorios que generé usando Falso. Y aquí está el resultado,
Conclusión
Definitivamente, la alternativa con un Entry Processor era la más rápida. Terminó en 12 milisegundos, mientras que el método Bulk terminó en 72 milisegundos. Con los Entry Processors, notamos una mejora en el rendimiento ya que ahorramos todos los viajes excesivos de la red al duplicar los puntos de nuestros clientes directamente en el servidor.
Eso es lo que son los procesadores de entrada y cómo funcionan. Aunque no escribimos un punto de referencia para probar esto NCache función, esta comparación nos da una idea de cómo utilizar los procesadores de entrada. Con ellos nos ahorramos algunos viajes de ida y vuelta a nuestro NCache servidor procesando nuestras entradas de caché directamente en un NCache servidor. La próxima vez que necesite actualizar algunas de sus entradas de caché, pruebe los procesadores de entrada.
Para obtener más detalles sobre cómo funcionan los procesadores de entrada, consulte Funcionamiento del procesador de entrada en caché.
Para seguir el código que escribimos en esta publicación, consulte mi NCache Repositorio de demostración en GitHub.