.NET Core e ASP.NET Core stanno guadagnando popolarità grazie alla loro semplicità di progettazione, essendo leggeri, open source e in grado di funzionare sia su Windows che su Linux. Di conseguenza, anche molte applicazioni esistenti stanno passando a .NET Core dal .NET Framework. Quasi tutte le nuove applicazioni sono in fase di sviluppo .NET Core.
Alcuni di questi .NET Core le applicazioni sono di natura ad alto traffico e servono milioni di utenti e transazioni. Di conseguenza, queste applicazioni hanno un enorme impatto sulla tua attività e sono quindi molto importanti.
I .NET Core le applicazioni che di solito richiedono scalabilità sono applicazioni server che devono elaborare molte transazioni molto rapidamente con tempi di risposta molto rapidi. Molte di queste applicazioni sono rivolte ai clienti, il che significa che elaborano le richieste dei clienti. Se non eseguono rapidamente le richieste dei clienti, il costo per l'azienda è elevato in termini di mancato guadagno e perdita di clienti soddisfatti.
A seguire .NET Core le applicazioni richiedono 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.
Ma, nonostante un'architettura molto scalabile a livello di applicazione, .NET Core le applicazioni server oggi devono affrontare gravi colli di bottiglia in termini di scalabilità. Questi colli di bottiglia si verificano in diverse aree come:
Il più grande collo di bottiglia per tutto il traffico intenso .NET Core applicazioni è il loro database dell'applicazione. La maggior parte delle applicazioni oggi utilizza ancora un database relazionale come SQL Server o Oracle. Questi database diventano rapidamente colli di bottiglia per la scalabilità man mano che aumenti i carichi delle transazioni su queste applicazioni. Questo è vero se si usa SQL Server in una macchina virtuale o in un database SQL di Azure.
Ciò accade perché un database relazionale non può essere partizionato logicamente come a NoSQL database e invece rimane in un luogo fisico; anche un certo partizionamento a livello di colonna non è per niente vero NoSQL partizione di stile. Pertanto, non è possibile aumentare la capacità di transazione del livello di database aggiungendo più server di database come è possibile con a NoSQL database.
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).
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 di SQL Server e Oracle non sono in grado di risolvere completamente il problema .NET Core esigenze di scalabilità dell'applicazione.
Uno dei motivi NoSQL databases è diventato popolare perché forniscono un corretto partizionamento dei dati basato su algoritmi basati su hash e altri. Ciò risolve molti dei problemi di scalabilità per la capacità di transazione che devono affrontare i database relazionali come SQL Server e Oracle.
Ma ci sono ragioni NoSQL databases non sono la soluzione ideale per questi colli di bottiglia del database.
La soluzione a tutti i problemi sopra menzionati è utilizzare una cache distribuita in memoria simile NCache nella vostra .NET Core distribuzione dell'applicazione. NCache è una cache distribuita Open Source per .NET e .NET Core che è estremamente veloce e linearmente scalabile. Pensalo come un archivio dati in memoria che viene anche distribuito. Essere in memoria lo rende estremamente veloce ed essere distribuito lo rende linearmente scalabile.
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 è tutto in memoria, è super veloce e ti offre tempi di risposta inferiori al millisecondo che non puoi aspettarti dai tuoi database relazionali o addirittura NoSQL databases.
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 ti consente di ridimensionare il tuo .NET Core applicazioni attraverso quanto segue:
Il collo di bottiglia più importante affrontato .NET Core applicazioni è il "Database delle applicazioni". La cosa bella di NCache è diverso NoSQL databases, 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
Un altro possibile collo di bottiglia è se memorizzi il tuo ASP.NET Core Sessioni in SQL Server o MemoryCache standalone. Entrambe le opzioni hanno grandi limiti in termini di prestazioni e scalabilità. L'archiviazione di SQL Server non è adatta per ASP.NET Core sessioni e diventa rapidamente un collo di bottiglia proprio come per i dati dell'applicazione.
NCache è un ottimo posto per memorizzare il tuo ASP.NET Core Sessions perché è molto più veloce e scalabile rispetto ad altre opzioni di archiviazione. NCache è più veloce perché è in memoria e fornisce un'interfaccia chiave-valore con il valore che è un "oggetto" che un ASP.NET Core La sessione è. Ed è scalabile perché è una cache distribuita.
E, NCache replica in modo intelligente anche ASP.NET Core sessioni attraverso le sue ricche topologie di memorizzazione nella cache, quindi anche se un server cache si interrompe, non si verifica alcuna perdita di dati di sessione. Questa replica è necessaria perché NCache fornisce un archivio in memoria e la memoria viola l'archiviazione.
NCache velocizza anche la serializzazione dell'ASP.NET Core Sessione necessaria prima che possa essere archiviata fuori processo. NCache lo fa utilizzando la sua funzionalità di serializzazione compatta dinamica che è 10 volte più veloce del normale .NET e .NET Core serializzazione. È possibile utilizzare questa funzione senza apportare modifiche al codice.
Puoi usare NCache come tuo ASP.NET Core Memorizzazione delle sessioni in due modi.
Di seguito è riportato un esempio di come è possibile configurare il proprio ASP.NET Core applicazione da usare 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 ASP.NET Core Sessioni
ASP.NET Core le applicazioni, che altrimenti hanno un contenuto piuttosto dinamico, affrontano situazioni in cui per alcune delle loro pagine il contenuto o la risposta non cambia su più richieste. Ma queste pagine devono ancora essere eseguite ogni volta che arriva la richiesta. E ciò comporta un onere non necessario sulle risorse del server Web e anche su tutti i livelli di questa applicazione. Di conseguenza, ciò aumenta anche i colli di bottiglia delle prestazioni e 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 ASP.NET Core Middleware della cache di risposta
Per affrontare il sovraccarico dell'esecuzione ripetitiva della pagina in cui la risposta della pagina non cambia, ASP.NET Core ha fornito un meccanismo di memorizzazione nella cache delle risposte di pagina chiamato ASP.NET Response Cache Middleware. E, NCache ha implementato l'interfaccia IDistributedCache in ASP.NET Core grazie al quale puoi collegarti senza problemi NCache come tuo ASP.NET Core Middleware della cache di risposta.
Quindi, puoi usare NCache per memorizzare nella cache ASP.NET Core risposte della pagina per un certo periodo di tempo, quindi la prossima volta che la stessa pagina viene chiamata con gli stessi parametri, questa risposta memorizzata nella cache può essere risintonizzata invece di eseguire nuovamente l'intera pagina. Di seguito è riportato l'esempio di codice su come configurare NCache come tuo ASP.NET Core Middleware della cache di risposta.
Se il tuo ASP.NET Core l'applicazione è un'applicazione Web in tempo reale, quindi è molto probabile che utilizzi 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. Gli esempi di tali applicazioni includono giochi, aste, votazioni, social network, ecc.
Se il tuo ASP.NET Core l'applicazione è in esecuzione in un ambiente multi-server con bilanciamento del carico, quindi deve utilizzare un ASP.NET Core SignalR Backplane provider per condividere eventi su più server web. E questo backplane deve essere scalabile. Altrimenti, il tuo ASP.NET Core L'applicazione SignalR inizia ad affrontare colli di bottiglia delle 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 ASP.NET Core SignalR Backplane Provider
NCache ha implementato un ASP.NET Core SignalR Backplane fornitore. NCacheè ASP.NET Core SignalR Backplane il provider utilizza le funzionalità di messaggistica Pub/Sub di NCache che sono super veloci perché sono totalmente in memoria. Ciò consente al tuo ASP.NET Core Applicazione SignalR per accelerare la propagazione degli eventi SignalR tra tutti i server Web e, di conseguenza, ai 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.
Se tuo .NET Core l'applicazione deve utilizzare la messaggistica Pub/Sub o gli eventi, quindi è molto probabile che utilizzi una piattaforma di messaggistica Pub/Sub che non è completamente in memoria e archivia invece tutti i messaggi sul disco. Di conseguenza, questo può facilmente diventare un collo di bottiglia delle prestazioni se la tua applicazione ha una transazione molto elevata.
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 il tuo .NET Core usi dell'applicazione 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 vostra .NET Core applicazione.
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 in .NET Core Apps
Il più grande collo di bottiglia di scalabilità che il tuo .NET Core l'applicazione deve rimuovere è dal database dell'applicazione. In quest'area, le tue applicazioni possono ottenere prestazioni elevate e scalabilità lineare tramite la memorizzazione nella cache dei dati delle applicazioni. Il motivo è semplice. Maggior parte .NET Core le applicazioni gestiscono molti dati avanti e indietro dal database.
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.
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.
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:
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.
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.
Read-through, write-through e write-behind offrono molti vantaggi al tuo .NET Core applicazioni tra cui:
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
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:
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
Traffico intenso .NET Core le applicazioni non possono permettersi di diminuire, soprattutto durante le ore di punta. Per questi tipi di applicazioni, ci sono tre obiettivi architetturali davvero importanti che piacciono a una buona InMemory Distributed Cache NCache soddisfa.
Lascia che ti spieghi ciascuno di seguito.
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.
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.
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: