ASP.NET sta diventando molto popolare per lo sviluppo di applicazioni Web e molte di queste applicazioni sono di natura ad alto traffico e servono milioni di utenti. Di conseguenza, queste applicazioni hanno un grande impatto sul business e sono quindi molto importanti.
È interessante notare che l'architettura dell'applicazione ASP.NET è molto scalabile a livello di applicazione. E anche il protocollo HTTP è senza stato. Entrambi significano che è possibile eseguire l'applicazione ASP.NET in una Web farm con bilanciamento del carico in cui ogni richiesta HTTP viene instradata al server Web più appropriato. Ciò ti consente di aggiungere facilmente più server Web alla tua web farm man mano che il traffico degli utenti aumenta. E questo rende il livello dell'applicazione ASP.NET molto scalabile. Ma cosa intendo per scalabilità qui?
La scalabilità è essenzialmente la capacità di fornire prestazioni elevate anche con carichi di picco. Pertanto, se il tempo di risposta della pagina dell'applicazione ASP.NET è molto veloce con 10 utenti e rimane altrettanto veloce con 100,000 utenti, l'applicazione ASP.NET è scalabile. Tuttavia, se il tempo di risposta ASP.NET rallenta all'aumentare del numero di utenti, l'applicazione non è scalabile.
Nonostante un'architettura molto scalabile a livello di applicazione, le applicazioni ASP.NET oggi devono affrontare gravi colli di bottiglia in termini di scalabilità. Questi colli di bottiglia si verificano in quattro aree diverse come segue:
Lascia che ti spieghi ciascuno in modo più dettagliato di seguito.
Il database delle applicazioni come SQL Server o Oracle diventa rapidamente un collo di bottiglia per la scalabilità man mano che aumenti il carico delle transazioni. Ciò accade perché, sebbene sia possibile aumentare il livello di database acquistando un server di database più potente, non è possibile eseguire la scalabilità orizzontale aggiungendo più server al livello di database. Ad esempio, è molto comune vedere 10-20 server a livello di applicazione, ma non è possibile fare lo stesso a livello di database.
Inoltre, lo stato della sessione ASP.NET deve essere archiviato da qualche parte. Inoltre, le opzioni predefinite fornite da Microsoft sono InProc, StateServer e SqlServer. Sfortunatamente, tutte e tre le opzioni presentano importanti problemi di prestazioni e scalabilità. InProc e StateServer ti obbligano a utilizzare sessioni permanenti e a inviare tutte le richieste HTTP sullo stesso server in cui è stata creata la sessione. Se si configura StateServer come server autonomo per evitare sessioni persistenti, StateServer diventa un singolo punto di errore e anche le sue prestazioni diventano un problema importante. Inoltre, SqlServer archivia le sessioni ASP.NET nel database di SQL Server come BLOB. E ci sono seri problemi di prestazioni e scalabilità con questo approccio.
ASP.NET View State è una stringa nascosta codificata (spesso di 100 KB di dimensione) che viene inviata al browser dell'utente come parte della risposta HTTP. Il browser non fa nulla con esso e lo restituisce al server web in caso di HTTP Post-Back. Ciò rallenta la risposta della pagina ASP.NET, aumenta il carico sulle schede di rete del server Web e consuma anche molta larghezza di banda aggiuntiva. E, come sai, la larghezza di banda non è economica.
Infine, l'ASP.NET framework esegue una pagina ASP.NET su una richiesta dell'utente, anche se l'output della pagina non cambia rispetto alla richiesta precedente. Questo può andare bene in ambienti a bassa transazione. Ma in un ambiente con transazioni elevate in cui stai già estendendo tutte le risorse ai loro limiti, questa esecuzione aggiuntiva può diventare piuttosto costosa e un collo di bottiglia per la scalabilità.
Come si suol dire "la forza di ogni catena è forte solo quanto il suo anello più debole". Pertanto, finché sono presenti colli di bottiglia di scalabilità in qualsiasi punto dell'ambiente applicativo ASP.NET, l'intera applicazione rallenta e si ferma persino.
E, ironia della sorte, questo accade nei picchi di carico quando si svolgono i più alti livelli di attività commerciale. Pertanto, l'impatto di qualsiasi rallentamento o fermo macchina è molto più costoso per il tuo business.
NoSQL database movimento è iniziato a causa dei problemi di scalabilità nei database relazionali. NoSQL database partiziona i dati su più server e ti consente di scalare verso l'esterno proprio come il livello dell'applicazione.
Ma, NoSQL database ti richiede di abbandonare il tuo database relazionale e di inserire i tuoi dati in a NoSQL database. E questo è più facile a dirsi che a farsi per una serie di motivi e in effetti non è possibile in molti casi.
NoSQL databases non hanno la stessa capacità di gestione e ricerca dei dati dei database relazionali e desiderano che i dati vengano archiviati in un modo completamente diverso da quello relazionale. Inoltre, l'ecosistema che circonda i database relazionali è troppo forte per essere abbandonato per la maggior parte delle aziende.
Come risultato, NoSQL databases sono utili solo quando hai a che fare con dati non strutturati. Inoltre, la maggior parte delle applicazioni ASP.NET tratta dati aziendali che sono prevalentemente strutturati e adatti ai database relazionali. Di conseguenza, questi dati non possono essere spostati in a NoSQL database facilmente.
E, anche quelli che finiscono per usare a NoSQL database farlo per un piccolo sottoinsieme dei loro dati totali che possono essere considerati non strutturati. E usano NoSQL database insieme al loro database relazionale esistente.
Pertanto, la maggior parte delle volte dovrai convivere con il tuo database relazionale e trovare un'altra soluzione per i tuoi problemi di scalabilità. Fortunatamente, esiste una soluzione molto praticabile e ne parlerò di seguito.
La soluzione a tutti i problemi sopra menzionati consiste nell'utilizzare la cache distribuita in memoria nella distribuzione dell'applicazione come NCache. NCache offre Cache distribuita open source per .NET che è estremamente veloce e linearmente scalabile. Pensalo come un negozio di oggetti in memoria che viene anche distribuito. Essere in memoria lo rende estremamente veloce ed essere distribuito lo rende linearmente scalabile.
La cosa bella di una cache distribuita in memoria come NCache è che non ti chiede di smettere di usare il tuo database relazionale esistente. È possibile utilizzare la cache sopra il database relazionale perché la cache rimuove tutti i colli di bottiglia della scalabilità del database relazionale.
Allora, com'è una cache distribuita in memoria NCache più scalabile di un database relazionale? Bene, NCache forma un cluster di server cache e raggruppa insieme la CPU, la memoria e altre risorse da tutti questi server.
E, NCache consente di aggiungere server di cache in fase di esecuzione senza interrompere la cache o l'applicazione. Inoltre, ciò ti consente di scalare linearmente la tua applicazione e gestire carichi di transazioni estremi. Questo è qualcosa che non puoi fare con il tuo database relazionale.
Cache distribuita in memoria come NCache scala in modo lineare consentendo di aggiungere server di cache al cluster di cache (il livello di memorizzazione nella cache) in fase di esecuzione. Ma che tipo di numeri di prestazioni dovresti aspettarti da una soluzione come NCache.
Qui di seguito sono NCache numeri di prestazione Puoi vedere tutto NCache benchmark delle prestazioni
Come puoi vedere, una cache distribuita in memoria piace NCache fornisce prestazioni inferiori al millisecondo per letture e scritture e consente di scalare la capacità delle transazioni in modo lineare semplicemente aggiungendo più server cache.
Vediamo ora come piace a una cache distribuita in memoria NCache risolve vari colli di bottiglia di scalabilità sopra menzionati.
La memorizzazione nella cache dei dati dell'applicazione consente di rimuovere i colli di bottiglia del database. Cache distribuita in memoria come NCache consente di memorizzare nella cache i dati dell'applicazione e ridurre i costosi viaggi del database. Puoi aspettarti di deviare il 70-90% del traffico del database alla cache distribuita in memoria. Ciò riduce la pressione sul database e gli consente di funzionare più velocemente e di gestire carichi di transazioni più grandi senza rallentamenti.
Customer Load(string customerId)
{
// Key format: Customer:PK:1000
string key = "Customers:CustomerID:" + customerId;
Customer cust = (Customer) _cache[key];
if (cust == null)
{ // Item not in cache so load from db
LoadCustomerFromDb(cust);
// Add item to cache for future reference
_cache.Insert(key, cust);
}
return cust;
}
Figura 4: utilizzo della cache distribuita in memoria per la memorizzazione nella cache dei dati delle app
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 su come utilizzare una cache distribuita come NCache per la memorizzazione nella cache dei dati dell'applicazione.
Cache distribuita in memoria come NCache è anche un ottimo posto per archiviare lo stato della sessione ASP.NET. È molto più veloce e scalabile di tutte e tre le opzioni sopra menzionate (InProc, StateServer e SqlServer). NCache è più veloce perché è in memoria e fornisce un'interfaccia valore-chiave con il valore che è un "oggetto" che è uno stato di sessione ASP.NET. Ed è scalabile perché è una cache distribuita.
E, NCache replica anche in modo intelligente le 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 della sessione. Questa replica è necessaria perché NCache fornisce un archivio in memoria e la memoria viola l'archiviazione.
NCache accelera inoltre la serializzazione dell'oggetto Session State ASP.NET necessario prima che possa essere archiviato fuori processo. NCache lo fa usando la sua funzionalità di serializzazione compatta dinamica che è 10 volte più veloce della normale serializzazione .NET. È possibile utilizzare questa funzione senza apportare modifiche al codice.
Puoi collegarti NCache Fornitore dello stato della sessione (SSP) all'applicazione ASP.NET apportando alcune modifiche al file web.config come mostrato di seguito.
<system.web>
...
<assemblies>
<add assembly="Alachisoft.NCache.SessionStoreProvider, Version=4.3.0.0,
Culture=neutral, PublicKeyToken=CFF5926ED6A53769" />
</assemblies>
<sessionState cookieless="false" regenerateExpiredSessionId="true"
mode="Custom" customProvider="NCacheSessionProvider"
timeout="20">
<providers>
<add name="NCacheSessionProvider"
type="Alachisoft.NCache.Web.SessionState.NSessionStoreProvider"
useInProc="false" cacheName="myDistributedCache"
enableLogs="false“ writeExceptionsToEventLog="false” />
</providers>
</sessionState>
...
</system.web>
Figura 5: plug-in NCache come ASP.NET Session State Provider (SSP) in Web.Config
Ho già descritto come ASP.NET View State è una stringa codificata inviata dal server web al browser dell'utente che poi la restituisce al server web in caso di HTTP Post Back. Ma, con l'aiuto di una cache distribuita InMemory come NCache, puoi memorizzarlo nella cache ASP.NET View State sul server e inviare solo un piccolo ID univoco al suo posto.
NCache ha implementato un ASP.NET View State modulo di memorizzazione nella cache tramite un adattatore di pagina ASP.NET personalizzato e ASP.NET PageStatePersister. Per di qua, NCache intercetta sia la richiesta che la risposta HTTP. Al momento della risposta, NCache rimuove la parte "valore" della stringa codificata e la memorizza nella cache e inserisce invece un identificatore univoco (una chiave cache) in questo "valore".
Quindi, quando arriva la successiva richiesta HTTP, la intercetta di nuovo e sostituisce l'identificatore univoco con la stringa codificata effettiva che ha inserito nella cache in precedenza. In questo modo, la pagina ASP.NET non nota nulla di diverso e utilizza la stringa codificata contenente lo stato di visualizzazione come prima.
L'esempio seguente mostra un ASP.NET View State stringa codificata senza memorizzazione nella cache e anche cosa succede quando viene incorporata la memorizzazione nella cache.
//ASP.NET View State without Caching
<input id="__VIEWSTATE"
type="hidden"
name="__VIEWSTATE"
value="/wEPDwUJNzg0MDMxMDA1D2QWAmYPZBYCZg9kFgQCAQ9kFgICBQ9kFgJmD2QWAgIBD
xYCHhNQcm2aW91c0NvbnRyb2xNb2RlCymIAU1pY3Jvc29mdC5TaGFyZVBvaW50Lld
lYkNvbnRyb2xzLlNQQ29udHJbE1vZDA1XzRlMjJfODM3Y19kOWQ1ZTc2YmY1M2IPD
xYCHhNQcm2aW91c0NvbnRyb2xNb2RlCymIAU1pY3Jvc29mdC5TaGFyZVBvaW50Lld
lYkNvbnRyb2xzLlNQQ29udHJbE1vZDA1XzRlMjJfODM3Y19kOWQ1ZTc2YmY1M2IPD
... ==" />
//ASP.NET View State with Caching
<input id="__VIEWSTATE"
type="hidden"
name="__VIEWSTATE"
value="vs:cf8c8d3927ad4c1a84da7f891bb89185" />
Figura 6: ASP.NET View State Stringa codificata con o senza memorizzazione nella cache
ASP.NET fornisce un ASP.NET Output Cache Framework per risolvere il problema dell'esecuzione eccessiva della pagina anche quando l'output della pagina non cambia. Questo framework ti consente di memorizzare nella cache l'output dell'intera pagina o di alcune parti della pagina in modo che la prossima volta che questa pagina verrà chiamata, non verrà eseguita e verrà invece visualizzato il suo output memorizzato nella cache. La visualizzazione di un output già memorizzato nella cache è molto più veloce che eseguire nuovamente l'intera pagina.
<caching>
<outputCache defaultProvider ="NOutputCacheProvider">
<providers>
<add name="NOutputCacheProvider"
type="Alachisoft.NCache.OutputCacheProvider.NOutputCacheProvider,
Alachisoft.NCache.OutputCacheProvider, Version=x.x.x.x,
Culture=neutral, PublicKeyToken=1448e8d1123e9096"
cacheName="myDistributedCache" exceptionsEnabled="false"
writeExceptionsToEventLog="false" enableLogs="true” />"
</providers>
</outputCache>
</caching>
Figura 7: configurazione del provider di cache di output ASP.NET per NCache in web.config
NCache ha implementato un provider di cache di output ASP.NET per .NET 4.0 o versioni successive. Ciò ti consente di collegarti NCache senza interruzioni e senza alcuno sforzo di programmazione. In caso di NCache, questo provider è per una cache distribuita in memoria che si estende su più server. Pertanto, se l'applicazione ASP.NET è in esecuzione in una Web farm con bilanciamento del carico, l'output della pagina memorizzato nella cache dal server 1 è immediatamente disponibile per tutti gli altri server nella Web farm. Di seguito è riportato come è possibile collegare NCache come provider di cache di output ASP.NET.
Le applicazioni ASP.NET ad alto traffico non possono permettersi di scendere soprattutto durante le ore di punta. Per questi tipi di applicazioni, ci sono tre importanti obiettivi architetturali che piacciono a una buona cache distribuita in memoria NCache fornisce. Sono:
Lascia che ti spieghi ogni area di seguito.
Uno degli obiettivi architettonici più importanti di NCache è quello di ottenere un'elevata disponibilità e l'elasticità della cache. E lo fa attraverso le seguenti capacità architettoniche:
Dal momento che la cache distribuita in memoria piace NCache utilizza la memoria come archivio, deve fornire la replica dei dati per garantire l'affidabilità. Ma, allo stesso tempo, non può compromettere la scalabilità lineare perché questo è il motivo più importante per utilizzare una cache distribuita come NCache.
Qui ci sono alcuni NCache Topologie di memorizzazione nella cache che aiutano a raggiungere entrambi questi obiettivi.
Come puoi vedere, Partitioned-Replica Cache inserisce una partizione e una replica su ciascun server cache. Inoltre, garantisce che la replica sia sempre su un server cache diverso per motivi di affidabilità.
Ho cercato di evidenziare i colli di bottiglia più comuni in termini di prestazioni e scalabilità che le applicazioni ASP.NET devono affrontare oggi e mostrarti come superarli utilizzando una cache distribuita in memoria come NCache. NCache è una cache distribuita Open Source per applicazioni .NET e Java. Quindi, puoi usarlo senza alcuna restrizione. Puoi saperne di più su NCache al seguente link