Scalabilità delle applicazioni .NET Core per prestazioni estreme

 

Introduzione

.NET Core e ASP.NET Core stanno guadagnando popolarità grazie alla loro semplicità di progettazione, alla leggerezza, al fatto di essere open source e di poter funzionare sia su Windows che su Linux. Di conseguenza, molte applicazioni esistenti stanno migrando da .NET Framework a .NET Core. Quasi tutte le nuove applicazioni vengono sviluppate in .NET Core.

Molte di queste applicazioni .NET Core sono caratterizzate da un elevato volume di traffico, servendo milioni di utenti e transazioni. Di conseguenza, queste applicazioni hanno un impatto enorme sulla tua attività e sono quindi di fondamentale importanza.

 

Chi ha bisogno della scalabilità?

Le applicazioni .NET Core che in genere necessitano di scalabilità sono applicazioni server che devono elaborare un gran numero di transazioni molto rapidamente, con tempi di risposta altrettanto rapidi. Molte di queste applicazioni sono rivolte direttamente ai clienti, ovvero elaborano le loro richieste. Se non riescono a evadere le richieste dei clienti in tempi brevi, il costo per l'azienda è elevato in termini di mancati ricavi e perdita di clienti soddisfatti.

Le seguenti applicazioni .NET Core richiedono scalabilità:

  1. Applicazioni Web (ASP.NET Core): Di solito si tratta di applicazioni rivolte ai clienti, ma potrebbero anche essere applicazioni interne per grandi aziende.
  2. Servizi Web (ASP.NET Core): Questi potrebbero fornire direttamente API Web ai clienti o potrebbero far parte di un'altra applicazione con transazioni elevate contenente la logica del livello dell'applicazione in questi servizi Web.
  3. Applicazioni Web in tempo reale (ASP.NET Core SignalR): Si tratta di applicazioni in tempo reale che devono fornire aggiornamenti frequenti agli utenti utilizzando il framework SignalR di ASP.NET Core. Devono inoltre essere veloci, poiché solitamente sono rivolte direttamente ai clienti.
  4. Microservizi (.NET Core): Si tratta di una nuova architettura applicativa per applicazioni lato server. E proprio come i servizi Web, questi microservizi fanno generalmente parte di un'applicazione Web rivolta al cliente o di un'applicazione di servizi Web rivolta al cliente. Di conseguenza, hanno anche requisiti di prestazioni elevate con carichi di transazioni pesanti.
  5. Altre applicazioni server (.NET Core): Esiste una ricca varietà di altre applicazioni server che devono elaborare una grande quantità di transazioni molto velocemente. Potrebbero essere applicazioni di elaborazione in batch che gestiscono vari tipi di flussi di lavoro di back-end o potrebbero essere applicazioni di elaborazione di flussi che ingeriscono una grande quantità di dati per un'elaborazione quasi in tempo reale. L'elenco continua.
 

Il problema: colli di bottiglia della scalabilità

È interessante notare che tutte le applicazioni sopra menzionate hanno architetture a livello di applicazione molto scalabili. Ognuno di essi ti consente di scalare linearmente all'aumentare del carico delle transazioni aggiungendo più server, macchine virtuali o istanze di container insieme a un sistema di bilanciamento del carico.

Nonostante un'architettura altamente scalabile a livello applicativo, le applicazioni server .NET Core oggi si trovano ad affrontare importanti colli di bottiglia in termini di scalabilità. Questi colli di bottiglia si verificano in diverse aree, come ad esempio:

  1. Database applicativi (database relazionali): Questo è il collo di bottiglia più grande di tutti. Lo spiego più dettagliatamente di seguito.
  2. Archiviazione della sessione ASP.NET Core: Se le sessioni vengono memorizzate in SQL Server, la tua applicazione ASP.NET Core incontrerà enormi colli di bottiglia.
  3. Elaborazione ripetitiva delle pagine in ASP.NET Core: Se le stesse pagine vengono eseguite ripetutamente e l'output o la risposta rimangono gli stessi, si tratta di uno spreco di risorse e di un collo di bottiglia delle prestazioni.
  4. Provider di backplane SignalR per ASP.NET Core: Se un'app Web live che utilizza SignalR deve essere ridimensionata, il relativo provider di backplane può facilmente diventare un collo di bottiglia.
  5. Messaggistica Pub/Sub (non in memoria): Se la tua applicazione .NET Core utilizza il sistema di messaggistica Pub/Sub, è probabile che non sia in memoria e che, di conseguenza, rappresenti un collo di bottiglia.
Colli di bottiglia delle prestazioni di ASP.NET Core
Figura 1: Applicazione ASP.NET Core alle prese con colli di bottiglia di scalabilità
 

Collo di bottiglia del database relazionale

Il principale collo di bottiglia per tutte le applicazioni .NET Core ad alto traffico è il database dell'applicazione. La maggior parte delle applicazioni odierne utilizza ancora un database relazionale come SQL Server o Oracle. Questi database diventano rapidamente un collo di bottiglia in termini di scalabilità all'aumentare del carico di transazioni sulle applicazioni. Questo vale sia che si utilizzi SQL Server su una macchina virtuale sia Azure SQL Database.

Questo accade perché un database relazionale non può essere partizionato logicamente come un database NoSQL e rimane invece in un'unica posizione fisica; anche un partizionamento a livello di colonna non è minimamente paragonabile a un vero partizionamento in stile NoSQL. Pertanto, non è possibile aumentare la capacità di transazione del livello del database aggiungendo altri server di database, come si può fare con un database NoSQL.

Ad esempio, mentre il livello dell'applicazione può facilmente avere 10, 20, 30 o più server delle applicazioni all'aumentare del carico delle transazioni, il livello del database non può crescere nello stesso modo.

Per questo motivo, il tuo database relazionale diventa un collo di bottiglia delle prestazioni per tutti i dati in esso archiviati (dati dell'applicazione o altri dati).

 

Le ottimizzazioni in memoria del server database non sono sufficienti

SQL Server ha introdotto ottimizzazioni in memoria per aumentare il numero di transazioni al secondo. Oracle ha anche fornito la propria versione delle tabelle In-Memory.

Sebbene le ottimizzazioni in memoria portino a miglioramenti delle prestazioni, non affrontano il problema principale della scalabilità lineare. Le tabelle in memoria vengono generalmente utilizzate per dati di sola lettura e per scalare una capacità di transazione di sola lettura, è necessario aggiungere più istanze di SQL Server su computer di fascia alta.

Le tabelle in memoria hanno anche limitazioni sulla dimensione dei dati; non puoi mettere in memoria tabelle di grandi dimensioni poiché l'intera tabella deve essere messa in memoria. E la loro replica su altre istanze di SQL Server può essere eseguita solo su altre tabelle in memoria e non su un database corretto.

In sintesi, queste ottimizzazioni in memoria nei database SQL Server e Oracle non sono in grado di soddisfare appieno le esigenze di scalabilità della tua applicazione .NET Core.

 

I database NoSQL non sono la soluzione.

Uno dei motivi per cui i database NoSQL sono diventati popolari è la loro capacità di partizionare correttamente i dati in base ad algoritmi di hash e ad altri metodi. Questo risolve molti dei problemi di scalabilità relativi alla capacità di gestione delle transazioni che affliggono i database relazionali come SQL Server e Oracle.

Tuttavia, esistono dei motivi per cui i database NoSQL non rappresentano la soluzione ideale per questi colli di bottiglia dei database.

  1. Non un negozio in memoria: I database NoSQL memorizzano i dati su disco proprio come i database relazionali. Ciò significa che, a prescindere da qualsiasi operazione si effettui, la lentezza del disco si traduce inevitabilmente in un collo di bottiglia per le prestazioni.
  2. Non può essere utilizzato la maggior parte del tempo: I database NoSQL richiedono di abbandonare i database relazionali come SQL Server e Oracle e di sostituirli con un database NoSQL. Nella maggior parte dei casi, ciò non è possibile per ragioni sia tecniche che non tecniche. In sostanza, la tua attività dipende dal database relazionale e non può abbandonarlo facilmente. Di conseguenza, non sei in grado di sfruttare appieno i vantaggi di un database NoSQL.
 

La soluzione: cache distribuita in memoria (NCache)

La soluzione a tutti i problemi sopra menzionati è utilizzare una cache distribuita in memoria simile NCache nella distribuzione della tua applicazione .NET Core. NCache è una cache distribuita open source per .NET e .NET Core estremamente veloce e con scalabilità lineare. Immaginatela come un archivio dati in memoria distribuito. Essendo in memoria, è estremamente veloce, mentre la distribuzione ne garantisce la scalabilità lineare.

NCache è linearmente scalabile perché crea un cluster TCP di server cache a basso costo (stessa configurazione dei server delle app Web ma con più memoria) e raggruppa la memoria e le risorse della CPU di tutti questi server in un'unica capacità logica. NCache quindi ti consente di aggiungere server di cache a questo cluster in fase di esecuzione all'aumentare del carico delle transazioni. E, da allora NCache È interamente in memoria, è velocissimo e offre tempi di risposta inferiori al millisecondo, cosa che non ci si può aspettare dai database relazionali o persino dai database NoSQL.

Oltre a fornire scalabilità lineare, una cache distribuita come NCache replica i dati in modo intelligente in modo che le tue prestazioni non vengano compromesse, garantendo al contempo l'affidabilità dei dati in caso di guasto di un server cache.

NCache Distribuito in ambito aziendale per .NET Core
Figura 2: NCache Distribuito in ambito aziendale per .NET Core

NCache consente di scalare le applicazioni .NET Core tramite le seguenti funzionalità:

  • Memorizzazione nella cache dei dati dell'applicazione
  • Archiviazione delle sessioni di ASP.NET Core
  • Middleware di cache di risposta ASP.NET Core
  • ASP.NET Core SignalR Backplane
  • Messaggistica Pub/Sub ed eventi CQ (in memoria)
  • Eventi di query continue (in memoria)
 

Memorizzazione nella cache dei dati dell'applicazione

Il collo di bottiglia più importante affrontato dalle applicazioni .NET Core è il "database dell'applicazione". La cosa bella di NCache è che, a differenza dei database NoSQL, NCache non ti chiede di smettere di usare il tuo database relazionale esistente. Puoi continuare a utilizzare SQL Server, database SQL di Azure, Oracle e così via come database e ottenere comunque una scalabilità lineare utilizzando NCache in cima al tuo database relazionale. Questo è perché NCache rimuove tutti i colli di bottiglia della scalabilità del database relazionale perché, a differenza del tuo database, NCache è in realtà linearmente scalabile.

La memorizzazione nella cache dei dati dell'applicazione consente di rimuovere i colli di bottiglia del database. NCache consente di memorizzare nella cache i dati dell'applicazione e ridurre i costosi viaggi del database. Puoi aspettarti di deviare l'80-90% del traffico del database verso NCache. Ciò riduce la pressione sul database e gli consente di funzionare più velocemente e di gestire carichi di transazioni più grandi senza rallentamenti.

La memorizzazione nella cache dei dati dell'applicazione significa memorizzare nella cache tutti i dati dell'applicazione ottenuti dal database relazionale. Questo di solito è sotto forma di oggetti di dominio (chiamati anche entità). Ecco un esempio di come utilizzare una cache distribuita come NCache per la memorizzazione nella cache dei dati dell'applicazione.

Customer Load(string custId)
{
  ICache cache = CacheManager.GetCache("myCache");
  string key = "Customer:CustomerID:" + custId;
  Customer cust = cache.Get<Customer>(key);
  
  if (cust == null)
  {
    // Item not in cache so load from db
    LoadCustomerFromDb(cust);
    // Add item to cache for future reference
    cache.Add(key, cust);
    }
    return cust;
}

Figura 3: utilizzo della cache distribuita in memoria per la memorizzazione nella cache dei dati delle app

 

Archiviazione delle sessioni di ASP.NET Core

Un altro possibile collo di bottiglia si presenta se si memorizzano le sessioni ASP.NET Core in SQL Server o in MemoryCache autonomo. Entrambe le opzioni presentano notevoli limitazioni in termini di prestazioni e scalabilità. L'archiviazione su SQL Server non è adatta alle sessioni ASP.NET Core e diventa rapidamente un collo di bottiglia, proprio come accade per i dati dell'applicazione.

NCache è un ottimo posto dove archiviare le sessioni ASP.NET Core perché è molto più veloce e scalabile rispetto ad altre opzioni di archiviazione. NCache È più veloce perché è in memoria e fornisce un'interfaccia chiave-valore in cui il valore è un "oggetto", quale è una Sessione ASP.NET Core. Inoltre, è scalabile perché è una cache distribuita.

E, NCache replica inoltre in modo intelligente le sessioni ASP.NET Core attraverso le sue ricche topologie di caching, in modo che anche se un server di cache si arresta, non si verifichi alcuna perdita di dati di sessione. Questa replica è necessaria perché NCache fornisce un archivio in memoria e la memoria viola l'archiviazione.

NCache Inoltre, velocizza la serializzazione della sessione ASP.NET Core, necessaria prima che possa essere memorizzata fuori dal processo. NCache Questo risultato viene ottenuto grazie alla funzionalità di serializzazione dinamica compatta, che è 10 volte più veloce della serializzazione standard di .NET e .NET Core. È possibile utilizzare questa funzionalità senza apportare alcuna modifica al codice.

Puoi usare NCache come archivio di sessioni ASP.NET Core in due modi.

  1. IDistributedCache per la sessione ASP.NET Core: NCache ha implementato l'interfaccia IDistributedCache che permette di inserire automaticamente i plug-in NCache come provider di Session Store per ASP.NET Core. Tuttavia, questa opzione offre meno funzionalità rispetto all'altra.
  2. NCache Provider per la sessione ASP.NET Core: NCache ha inoltre implementato un proprio provider di Session Store ASP.NET Core più ricco di funzionalità che è possibile utilizzare. Offre più funzionalità in termini di blocco aggiuntivo, timeout, ecc.

Di seguito è riportato un esempio di come è possibile configurare l'applicazione ASP.NET Core per utilizzare NCache Fornitore della sessione:

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // Specify NCache as the session provider
    services.AddNCacheSession(Configuration.GetSection("NCacheSettings"));
    ...
  }
    
  public void Configure(IApplicationBuilder app, ...)
  {
    // select NCache session provider for ASP.NET Core
    app.UseNCacheSession();
    ...
  }
}

Figura 4: plug-in NCache come sessioni ASP.NET Core

 

Middleware di cache di risposta ASP.NET Core

Le applicazioni ASP.NET Core, che altrimenti presentano contenuti piuttosto dinamici, si trovano ad affrontare situazioni in cui, per alcune pagine, il contenuto o la risposta non cambiano tra una richiesta e l'altra. Tuttavia, queste pagine devono essere eseguite ogni volta che arriva una richiesta. Ciò comporta un carico eccessivo sulle risorse del server web e su tutti i livelli dell'applicazione. Di conseguenza, si creano colli di bottiglia nelle prestazioni e si limita la scalabilità dell'applicazione.

public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // Turn on ASP.NET Core Response Cache with IDistributedCache
    services.AddResponseCaching();
    
    // Select NCache as IDistributedCache provider
    services.AddNCacheDistributedCache(Configuration.GetSection("NCacheSettings"));
    ...
  }
}

Figura 5: plug-in NCache come middleware di cache di risposta ASP.NET Core

Per affrontare il sovraccarico dell'esecuzione ripetitiva della pagina quando la risposta della pagina non cambia, ASP.NET Core ha fornito un meccanismo di caching della risposta della pagina chiamato ASP.NET Response Cache Middleware. E, NCache ha implementato l'interfaccia IDistributedCache in ASP.NET Core grazie alla quale è possibile collegarla senza problemi NCache come middleware di cache di risposta per ASP.NET Core.

Quindi, puoi usare NCache per memorizzare nella cache le risposte delle pagine ASP.NET Core per un certo periodo di tempo, in modo che la prossima volta che la stessa pagina viene chiamata con gli stessi parametri, questa risposta memorizzata nella cache possa essere restituita invece di eseguire nuovamente l'intera pagina. Di seguito è riportato un esempio di codice su come configurare NCache come middleware di cache di risposta per ASP.NET Core.

 

ASP.NET Core SignalR Backplane

Se la tua applicazione ASP.NET Core è un'applicazione web in tempo reale, molto probabilmente utilizza ASP.NET Core SignalR per fornire questo comportamento in tempo reale. Le applicazioni web in tempo reale forniscono aggiornamenti ad alta frequenza dal server al client. Esempi di tali applicazioni includono giochi, aste, votazioni, social network, ecc.

Se la tua applicazione ASP.NET Core è in esecuzione in un ambiente multi-server con bilanciamento del carico, deve utilizzare un provider SignalR Backplane per ASP.NET Core per condividere gli eventi tra più server web. Inoltre, questo Backplane deve essere scalabile. In caso contrario, la tua applicazione SignalR per ASP.NET Core inizierà a presentare colli di bottiglia nelle prestazioni.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Specify NCache as the ASP.NET Core SignalR Backplane
        services.AddSignalR().AddNCache(ncacheOptions =>
        { ncacheOptions.CacheName = "myPartitionedCache"; });
        ...
    }
    
    public void Configure(IApplicationBuilder app, ...)
    {
        // Use SignalR in ASP.NET Core
        app.UseSignalR(config => { config.MapHub<MessageHub>("/messages"); });
        ...
    }
}

Figura 6: plug-in NCache come provider di backplane SignalR per ASP.NET Core

NCache ha implementato un provider di backplane SignalR per ASP.NET Core. NCacheIl provider di backplane SignalR di ASP.NET Core utilizza le funzionalità di messaggistica Pub/Sub di NCache che sono estremamente veloci grazie al fatto di essere completamente in memoria. Ciò consente alla tua applicazione ASP.NET Core SignalR di accelerare la propagazione degli eventi SignalR tra tutti i server web e, di conseguenza, verso i client.

E questo rende la tua applicazione web in tempo reale più reattiva nel fornire quegli aggiornamenti frequenti ai clienti. Inoltre, puoi continuare ad aumentare il numero di client e anche aggiungere più server Web senza temere colli di bottiglia delle prestazioni.

 

Messaggistica Pub/Sub (in memoria)

Se la tua applicazione .NET Core deve utilizzare la messaggistica Pub/Sub o gli eventi, è molto probabile che utilizzi una piattaforma di messaggistica Pub/Sub non completamente in memoria, ma che memorizza tutti i messaggi su disco. Di conseguenza, questo può facilmente diventare un collo di bottiglia per le prestazioni se la tua applicazione gestisce un numero elevato di transazioni.

NCache fornisce anche una messaggistica Pub/Sub che è super veloce perché è completamente in memoria. E replica tutti i messaggi su un altro NCache server per garantire che non si tratti di una perdita di dati in caso di inattività di un server.

Pertanto, se la tua applicazione .NET Core utilizza NCache come piattaforma di messaggistica Pub/Sub, sperimenterà prestazioni super veloci e scalabilità lineare perché NCache di per sé è linearmente scalabile.

Di seguito è riportato un esempio di come utilizzare Pub/Sub Messaging fornito da NCache nella tua applicazione .NET Core.

private void PublishMessage (string topicName)
{
    ITopic topic = _cache.MessagingService.GetTopic(topicName);
    Order order = Order.GenerateOrder<Order>();
    // Publish message containing "order" with expiry
    Message message = new Message(order, new TimeSpan(0, 0, 15));
    topic.Publish(message, DeliveryOption.All, true);
}

private ITopicSubscription SubscribeMessage (string topicName)
{
    ITopic topic = _cache.MessagingService.GetTopic(topicName);
    // Subscribes to the topic. Message delivered to MessageReceivedCallback
    return topic.CreateSubscription(MessageReceivedCallback);
}
static void MessageReceivedCallback(object sender, MessageEventArgs args) { ... }

Figura 7: Utilizzo della messaggistica Pub/Sub nelle app .NET Core

 

Memorizzazione nella cache dei dati dell'applicazione

Il principale collo di bottiglia in termini di scalabilità che la tua applicazione .NET Core deve eliminare è rappresentato dal database dell'applicazione. In quest'area, le tue applicazioni possono raggiungere prestazioni elevate e scalabilità lineare grazie alla memorizzazione nella cache dei dati. Il motivo è semplice: la maggior parte delle applicazioni .NET Core gestisce un'enorme quantità di dati in entrata e in uscita dal database.

 

Mantieni la cache fresca

Quando si tratta di memorizzazione nella cache dei dati delle applicazioni, la più grande paura che le persone hanno è che la cache diventi obsoleta, il che significa che contiene una versione precedente dei dati che è già stata modificata nel database da un altro utente o da un'altra applicazione.

  1. Riferimento vs dati transazionali

    Questa paura che una cache diventi obsoleta è così forte che la maggior parte delle persone memorizza nella cache solo dati statici o di sola lettura (dati di riferimento). Tuttavia, questi dati di sola lettura rappresentano solo il 20% dei dati totali sotto forma di tabelle di ricerca e altri dati di riferimento. La maggior parte dei dati nel database è transazionale, inclusi clienti, account, attività, ecc. E, se non si memorizzano nella cache questi dati transazionali, non si beneficia completamente della memorizzazione nella cache.

    Quindi, il vero vantaggio della memorizzazione nella cache viene se puoi memorizzare nella cache tutti i tipi di dati senza il timore che la memorizzazione nella cache diventi obsoleta. NCache fornisce una serie di funzionalità per affrontare questo problema.

  2. Sincronizza la cache con il database

    Il modo più efficace per mantenere aggiornata la cache è mantenerla sempre sincronizzata con il database. NCache ti consente di farlo su una varietà di database come segue:

    1. Sincronizza cache con SQL Server: utilizzando SqlDependency e notifiche di eventi DB
    2. Sincronizza la cache con Oracle: utilizzando OracleDependency e le notifiche di eventi DB
    3. Sincronizza cache con Cosmos DB: utilizzando Cosmos DB Modifica feed di elaborazione
    4. Sincronizza la cache con qualsiasi database (basato sul polling): utilizzando NCache ha fornito la sincronizzazione del database basata su polling.

Quando sincronizzi la tua cache con SQL Server, chiedi NCache per registrarsi come client di SQL Server e quindi eseguire una chiamata SqlDependency insieme a un set di dati basato su query SQL. Quindi, quando SQL Server rileva eventuali modifiche in questo set di dati, invia una notifica NCache a proposito

private static void CreateSqlDependency (Product product)
{
    string connectionString = "Data Source=localhost;Database=northwind;...";
    // SQL stmt on which the SQL Dependency is created in SQL Server
    string sqlStmt = "SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice " +
    "FROM dbo.PRODUCTS WHERE ProductID = " + product.Id;
    CacheDependency sqlDependency = new SqlCacheDependency(connectionString, sqlStmt);
    CacheItem cacheItem = new CacheItem(product) { Dependency = sqlDependency };
    string key = "Product:ProductId:" + product.Id; ;
    cache.Add(key, cacheItem);
}

Figura 8: utilizzo di SqlDependency per sincronizzare la cache con SQL Server

Poi, NCache rimuove questo elemento dalla cache, quindi la prossima volta che l'applicazione ne avrà bisogno, dovrà recuperare l'ultima copia dal database. Se stai usando il gestore Read-through (vedi sotto), allora NCache può anche ricaricare automaticamente l'ultima copia dal database per te. Di seguito è riportato un esempio di come utilizzare SqlDependency per sincronizzare la cache con SQL Server.

 

Cache di lettura e scrittura

La cache di lettura è una cache in grado di leggere i dati dal database chiamando un gestore di lettura che hai sviluppato e fornito alla cache. Allo stesso modo, una cache di scrittura è in grado di scrivere le modifiche ai dati nel database chiamando un gestore di scrittura che hai sviluppato e fornito alla cache. La cache write-behind è la stessa di quella write-through, tranne per il fatto che gli aggiornamenti del database vengono eseguiti in modo asincrono.

Le funzionalità di lettura diretta (Read-through), scrittura diretta (Write-through) e scrittura differita (Write-behind) offrono numerosi vantaggi alle applicazioni .NET Core, tra cui:

  1. Semplifica il codice dell'app: Sposta il codice di persistenza dall'applicazione al livello di memorizzazione nella cache.
  2. Ricarica automaticamente gli elementi da DB: Utilizzare Read-through alla scadenza o tempo di sincronizzazione DB.
  3. Scrive più veloci: Usa scritture asincrone di database con write-behind.

Di seguito è riportato un esempio di come utilizzare Read-through con NCache.

// Read through handler for SQL Server
public class SqlReadThruProvider : Runtime.DatasourceProviders.IReadThruProvider
{
    public void Init(IDictionary parameters, string cacheId) {}
    public void Dispose() {}
    // Get object from the database/data-source based on the key
    public ProviderCacheItem LoadFromSource(string key) {}
    // Bulk-Get objects from the database/data-source based on the keys
    public IDictionary<string, ProviderCacheItem> LoadFromSource(ICollection<string> keys)
    {}
}

Figura 9: utilizzo di Read-through Handler con NCache

 

Cerca nella cache

Una volta che sei a tuo agio nella memorizzazione nella cache di tutti i dati, puoi iniziare a inserire molti dati in una cache distribuita. Qui puoi iniziare ad affrontare un altro problema peculiare di come trovare rapidamente e facilmente i tuoi dati. Poiché la maggior parte delle cache distribuite sono archivi di valori-chiave, diventa molto difficile tenere traccia di tutti i dati solo tramite le chiavi.

Qui è dove NCache ti offre una varietà di modi per trovare rapidamente i dati dalla tua cache. Esempi inclusi:

  1. Raggruppare i dati nella cache (gruppo/sottogruppo, tag, tag con nome): NCache ti offre diversi modi per raggruppare i tuoi dati in modo logico e poi recuperare l'intero gruppo in una chiamata. Questo semplifica davvero la gestione dei dati.
  2. Cerca dati con query (SQL/LINQ): oltre a trovare dati basati su chiamate API di gruppo, NCache ti dà anche la possibilità di cercare i dati nella cache in base agli attributi degli oggetti, ai gruppi, ai tag e ai tag con nome.
  3. Ricerche parallele: dal NCache è distribuito in natura, quando l'applicazione emette una query di ricerca o una chiamata API di ricerca, tale query viene eseguita in parallelo su tutti i server di cache. Quindi i risultati di tutti i server vengono restituiti alla macchina client (ovvero il server delle applicazioni) dove vengono uniti prima di restituire i risultati finali all'applicazione. Questo velocizza davvero le tue ricerche nella cache.

Di seguito è riportato un esempio di come utilizzare le query basate su LINQ con NCache.

// Search the cache based on object attributes by using LINQ
IQueryable>Product< products = new NCacheQuery<Product>(_cache);
var result = from product in products
where product.Id > 10
select product;
if (result != null)
{
    foreach (Product p in result1)
    {
        // Process each “product” fetched from the database
        Console.WriteLine("ProductID : " + p.Id);
    }
}

Figura 10: utilizzo di query LINQ con NCache

 

NCache Architettura per una scalabilità estrema

Le applicazioni .NET Core ad alto traffico non possono permettersi di andare in crash, soprattutto durante le ore di punta. Per questo tipo di applicazioni, ci sono tre obiettivi architetturali davvero importanti che una buona cache distribuita in memoria come NCache soddisfa.

  1. Cache client (velocità InProc)
  2. Scalabilità lineare con replica veloce
  3. Alta disponibilità grazie al clustering dinamico

Lascia che ti spieghi ciascuno di seguito.

 

Cache client (velocità InProc)

NCache fornisce una cache client che è una cache locale molto vicina alla tua applicazione. Può essere InProc (il che significa che risiede all'interno del processo di applicazione) o OutProc locale. In ogni caso, fornisce un accesso molto rapido a un sottoinsieme dei dati memorizzati nella cache di cui la tua applicazione su questo server app ha bisogno in questo momento. Allo stesso tempo, la cache del client rimane sincronizzata con il livello di memorizzazione nella cache, quindi tutti i dati modificati da altri utenti o applicazioni nel livello di memorizzazione nella cache vengono immediatamente propagati alla cache del client. Il client ti consente di avere la velocità di InProc pur facendo parte di un livello di memorizzazione nella cache molto scalabile.

Architettura della cache del cliente in NCache per InProc Speed
Figura 11: architettura della cache del client in NCache per InProc Speed
 

Scalabilità lineare con replica rapida

Uno degli obiettivi architettonici più importanti di NCache è ottenere una scalabilità lineare con affidabilità dei dati attraverso le sue topologie di memorizzazione nella cache. Eccotene alcune NCache Topologie di memorizzazione nella cache che aiutano a raggiungere entrambi questi obiettivi.

  1. Cache partizionata: NCache partiziona la cache in base al numero di server cache e assegna una partizione a ciascun server cache. Regola anche il numero di partizioni quando aggiungi o rimuovi server cache in fase di esecuzione. Il partizionamento è il modo principale per garantire la scalabilità lineare perché quando si aggiungono più server, questa topologia di memorizzazione nella cache aumenta la dimensione complessiva dello storage e anche la potenza di elaborazione della CPU.
  2. Cache della replica partizionata: Oltre al partizionamento, NCache fornisce anche repliche per ogni partizione. Queste repliche risiedono su server cache diversi rispetto alla partizione stessa per garantire che se un server cache si interrompe insieme alla relativa partizione, la replica diventi immediatamente disponibile. In questo modo viene garantita l'affidabilità dei dati. Replicando ogni partizione solo una volta su un altro server cache, NCache raggiunge l'affidabilità dei dati senza compromettere la scalabilità lineare.
Topologia di memorizzazione nella cache di partizione-replica di NCache
Figura 12: Topologia di memorizzazione nella cache di partizione-replica di NCache
 

Alta disponibilità per un tempo di attività del 100%.

Uno degli obiettivi architettonici più importanti di NCache è quello di ottenere un'elevata disponibilità e l'elasticità della cache. Lo fa attraverso le seguenti capacità architettoniche:

  1. Cluster di cache peer-to-peer con riparazione automatica: NCache crea un cluster di server cache su TCP/IP. Questo cluster ha a architettura peer-to-peer ciò significa che non ci sono nodi master/slave e nessun clustering con regole di maggioranza. Invece, ogni nodo è un peer uguale. Ciò consente NCache per gestire situazioni in cui qualsiasi nodo potrebbe interrompersi e il cluster si adatta automaticamente e continua a funzionare e non si verificano interruzioni per l'applicazione.
  2. Configurazione dinamica: Ciò significa che non è necessario codificare le cose nei file di configurazione. NCache propaga le informazioni di configurazione a tutti i client cache (ovvero le tue applicazioni) in fase di esecuzione.
  3. Supporto per il failover della connessione: Se un server della cache si interrompe, l'intero cluster della cache e tutti i client della cache possono continuare a funzionare senza alcuna interruzione. I client cache continuano a funzionare interagendo con altri server cache nel cluster.

Cosa fare dopo?

© Copyright Alachisoft 2002 - . Tutti i diritti riservati. NCache è un marchio registrato di Diyatech Corp.