2009-09-28 10 views
14

Recentemente ho eseguito alcuni test delle prestazioni e analisi di un'applicazione ASP.NET utilizzando lo stato di sessione out-of-process, necessario quando si utilizza lo stato di sessione in una Web farm in modo che lo stato possa essere recuperato su uno qualsiasi dei server Web, ad es se successive richieste HTTP arrivano a un server diverso perché le sessioni non sono "appiccicose" o il server originale è inattivo, ecc.Possibili soluzioni a prestazioni scadenti di serializzazione

Ciò che mi ha sorpreso è che quando eseguivo i server Web a pieno carico e profilavo l'utilizzo della CPU qualcosa come il 99% del tempo della CPU è stato impiegato per serializzare e deserializzare lo stato della sessione. Successivamente abbiamo implementato un server di stato "caching" personalizzato; questo sempre serializza lo stato ma mantiene anche lo stato in memoria in modo tale che se si usano sessioni adesive lo stato non deve essere deserializzato il più delle volte. Questo ha migliorato il throughput del server di un fattore 2; Tuttavia, la serializzazione rappresenta ancora il 98% o più del tempo di CPU.

Abbiamo ottenuto ulteriori miglioramenti in termini di velocità tagliando i riferimenti di oggetti non necessari tra gli oggetti nello stato della sessione prima della serializzazione, risolvendo manualmente i riferimenti dopo la desrializzazione. Questa velocità migliorata di un altro 10-20% circa. Il ragionamento qui è che parte della perdita di prestazioni è dovuta alla serializzazione incorporata che deve percorrere il grafico dei puntatori di oggetti, che diventa un compito più complesso con più puntatori.

Continuando l'indagine abbiamo scritto routine di serializzazione personalizzate per alcune delle nostre classi piuttosto che basarci sulla serializzazione integrata di .Net. Quello che abbiamo trovato è stato che la performance era notevolmente migliorata, di un fattore di circa 50x. Sembra che la maggior parte del carico della CPU sia causata dalla serializzazione .Net, che a sua volta è lenta a causa dell'utilizzo di Reflection per percorrere i puntatori/grafici degli oggetti ed estrarre i dati del campo.

È molto allettante aumentare le nostre prestazioni di 50 volte, riducendo così i requisiti hardware del server Web di un fattore importante (e i requisiti di alimentazione di un fattore minore ma ancora significativo). Le opzioni attualmente disponibili sono:

1) Scrivi la serializzazione personalizzata. Questo è un problema dovuto alla complessità del task e al sovraccarico di manutenzione che genera, ovvero qualsiasi modifica allo stato della classe richiede una modifica alle routine di serializzazione/deserializzazione.

2) Alcune soluzioni di terze parti. Forse un prodotto che genera automaticamente il salvataggio/caricamento di stato in fase di compilazione, eliminando così la necessità di utilizzare Reflection.

Sarei molto interessato a sapere se qualcuno sa di una soluzione di terze parti, o ha riscontrato questo problema in quanto non ho trovato alcuna menzione da ricerche su Internet.

AGGIORNAMENTO: Alcuni hanno suggerito una sorta di soluzione a metà strada tra la serializzazione incorporata predefinita e le routine di serializzazione personalizzate. L'idea è di implementare la serializzazione personalizzata per le classi che influiscono maggiormente sulle prestazioni, ad es. eccessiva ISerializable. Questo è un approccio interessante e promettente; Tuttavia ritengo ancora che ci sia spazio per una sostituzione completa della serializzazione integrata senza dover scrivere e mantenere alcun codice personalizzato - questo non può essere fatto in fase di esecuzione perché Reflection è necessario per interrogare oggetti e accedere ai dati privati. Ma è teoricamente possibile post-elaborare gli assembly già costruiti e iniettare nuovi metodi come passo aggiuntivo. Alcuni profiler usano questo approccio per iniettare il codice di profilazione negli assembly dopo che sono stati compilati dal compilatore C#. Anch'io penso/leggo da qualche parte che il framework .Net supporti i metodi di iniezione in classi - quindi tutto il caos con IL è potenzialmente preso in considerazione.

+0

Abbastanza sicuro che i metodi di iniezione di cui si parla sarebbero l'uso di classi parziali. Penso che il principio sia se due classi nello stesso namespace hanno lo stesso nome e una è contrassegnata come parziale. Una dll è prodotta incorporando metodi e proprietà di entrambe le classi. – Robert

risposta

2

Sfortunatamente sono a conoscenza dell'opzione 1 e di quella che può iniziare a diventare molto dolorosa su cui lavorare.

Ma fa solo quello che vuoi quindi è il più veloce che ottiene.

Buona fortuna.

+0

Accetto questo come risposta perché abbiamo rilevato che tutte le altre soluzioni sono almeno 10 volte più lente della scrittura di codice personalizzato. – redcalx

1

Un'altra opzione è disabilitare in modo aggressivo ViewState su tutti i controlli che non vengono toccati sui postback lato server.

+0

Gran parte dello stato proviene dalle nostre classi, ma sì, ci sarà lo stato dei controlli ASP.NET standard, quindi vale sicuramente la pena tenerlo d'occhio. Grazie. – redcalx

1

È possibile personalizzare parzialmente la serializzazione implementando ISerializable. Se lo fai per i peggiori trasgressori, non aumenterai più la manutenzione, ma otterrai comunque un po 'di velocità.

+0

Volevo aggiungere che nei nostri test di recente abbiamo riscontrato che questo non migliora le prestazioni. Sembra che il risultato della performance sia dal codice che segue il grafico dell'oggetto - la gestione dei dati effettiva non è il bit più lento! – redcalx

1

c'è una soluzione di terze parti: eccellente libreria open source

Simon Hewitt, vedere Optimizing Serialization in .NET - part 2.

Sono using it in my application e ho ottenuto un simile acceleratore come voi, 20-40 volte.

Elimina il riflesso che causa il rallentamento dello , ma per gli elenchi supporta solo alcuni tipi nativi. Quindi per Genreric.List dei tuoi stessi tipi ci deve essere il codice esplicito da qualche parte o l'altro. Per esempio. loop espliciti o qualcosa di più intelligente che lo automatizza. In ogni caso è piuttosto semplice e non dovrebbe essere di ostacolo per i benefici enormi .

+0

Grazie, molte informazioni interessanti qui. A prima vista sembra essere posizionato a metà strada tra l'utilizzo della serializzazione integrata (lenta) e pura. E 'piggyback sulla serializzazione integrata che è stata anche suggerita da una delle altre risposte. – redcalx

0

Abbiamo riscontrato problemi simili e abbiamo escogitato diversi modi per migliorare le prestazioni. Usiamo alcuni di questi nel nostro prodotto di mappatura della memoria di Persistore (attualmente beta). Nel nostro caso possiamo semplicemente accedere ai dati persistenti "in situ" perché è sempre presente in un heap mappato in memoria.

Tuttavia, un 'trucco' è quello di definire i dati dello stato sessione (se possibile) come marshalable classe/struttura e 'serializzare' che utilizzando il supporto .NET smistamento, questo può essere molto velocemente, ma non gestirà grafici 'oggetto'.

Supporta anche una persistenza speciale basata sulla serializzazione binaria, ma estrapiamo e persistono anche i metadati in modo che il codice gestito possa impostare/ottenere campi all'interno di un dato di memoria persistente in fase di runtime senza la necessità di deserializzare l'intero oggetto, questo è utile in alcune impostazioni (ad esempio, titoli e aggiornamenti dei prezzi delle azioni ecc.). La nostra ultima versione beta supporta la serializzazione su una rete, di tipi anonimi LINQ , questo è il primo per quanto ne so.

In ogni caso, saremmo interessati ad avere alcuni nuovi clienti beta che stanno spingendo ASP.NET e problemi di prestazioni web, la nostra ultima beta è molto impressionante (ma non è pronta fino alla settimana nex).

Se qualcuno è curioso contattateci per le ultime informazioni sul prodotto.

Hugh Moran

PS: sito web non è aggiornato, il prodotto va ben oltre quanto descritto lì.

Problemi correlati