38 messaggi dal 20 ottobre 2009
Ciao ragazzi, la cosa non è semplice a spiegare ma cercherò di sintetizzare...abbiamo poco tempo tutti :)

In pratica ho un server dedicato su Aruba (non fate commenti su Aruba, solo e quando passi a server dedicato le cose cmq non sono poi così male come si racconta...) in cui ho messo la mia applicazione e il mio bel DB su Sql server 2005 Standard edition. Ho configurato il tutto per prestazioni ottimali, sia IIS 6.0, Application Pool e su Sql Server ho lasciato le impostazioni standard come Max memory limit e max worker threads lasciati di default. La macchina ha una CPU Dual 2x core 1,60Ghz, Hd 160GB e 2GB di RAM. Ciò che accade è che quando faccio un pò di pubblicità al mio sito e il carico di accessi s'intensifica (ho toccato picchi di circa 30-40 richieste al secondo) l'applicazione inizia a dare dei numeri; alcune operazioni di scrittura sul DB saltano, altre vengono fatte in modo anomalo e i SqlCommand che ho usato danno errori molto strani (Index out of bound of array etc..). Ho provato a monitorare l'attività con il task manager ed ho notato che la CPU era praticamente quasi sempre al 100% (processi w3wp.exe e sqlserv.exe erano i responsabili...maggiormente il sqlserv.exe) mentre la memoria circa ad 1,55GB quindi in prima istanza presumo di tratti di un problema di I/O e non di memoria. Premetto che tale identico problema mi capitava anche quando il DB era invece in hosting condiviso e l'applicazione era su Server Virtuale: quando si alzava il carico riapparivano gli identici problemi. Ho controllato le mie query e soltanto 2-3 (assieme a qualche Stored Procedure) sono più "toste" (che presto riscriverò meglio) che impiegano circa 1200ms ma quando il carico è diciamo basso questi problemi non si verificano e tutto funziona regolare. Avendo anche un Server Virtuale (di caratteristiche simili a quelle dette per il server dedicato) ho fatto un altro tentativo ed ho spostato l'intero DB su esso e mantenuto l'applicazione sul Server Dedicato e sembra andar meglio ma anche in questo scenario ho riscontrato qualche piccola anomalia identica alle precedenti anche se in misura minore. La cosa che è certa è che cmq la RAM viene usata intensivamente ma ciò è proprio di SQL Server per il buffer pool, ma quest'ultima non raggiunge mai il limite massimo fisico disponibile sulla macchina (verificato anche con un profiler...)

Il mio sospetto è che si tratti proprio di I/O, ovvero che il disco che è un SATA non riesca a svolgere in modo ottimale tutte le operazioni di lettura/scrittura quando l'applicazione è sotto carico. Difatti voglio operare adesso la soluzione inversa, ovvero passare l'applicazione su Server Virtuale e spostare il DB sul Dedicato, aumentando la memoria a 4GB e dedicando così un intera macchina al solo DB.

vi è mai capitata una cosa del genere, cosa ne pensate ?

Grazie a tutti coloro che mi daranno attenzione!

Ci sono solo 10 categorie di persone al mondo: quelle che non conoscono il binario e quelle che lo conoscono.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao, sei sicuro che si tratti di un problema di I/O? Ho l'impressione che, se così fosse, la CPU sarebbe in idle per una certa parte del tempo mentre dalle tue rilevazioni risulta essere costantemente al 100%.
Comunque, per esaminare la questione più a fondo, utilizza il Performance Monitor per avere letture più accurate su singoli indicatori.

Spostare il db su un altro server allevierà sicuramente il carico sulla CPU ma tieni presente che, al contempo, la latenza di accesso ai dati aumenterà e se il problema è effettivamente di I/O le prestazioni potrebbero anche diminuire. A quel punto forse sarebbe meglio aggiungere un altro disco allo stato solido solo per i dati, se previsto dal tuo gestore.

Credo che si potrebbe ridurre il problema alla fonte se si limitassero gli accessi al database. Dato che hai ancora un po' di RAM disponibile, prova ad inserire in cache i risultati delle query più ricorrenti.
Inoltre, per cercare di ridurre il carico sulla CPU, usa l'OutputCache sia su usercontrols che su intere pagine, quando possibile.

A questo punto, volendo migliorare le prestazioni ulteriormente, potresti creare una versione denormalizzata del tuo database e riscrivere le SELECT affinché usino quella. Le letture sarebbero più veloci perché non saranno più necessarie delle JOIN per ricomporre i dati che prima erano spalmati su più tabelle.
Se ti interessa l'argomento, inizia da questo articolo su CQRS (Command and Query Responsibility Segregation).
http://blog.fossmo.net/post/Command-and-Query-Responsibility-Segregation-%28CQRS%29.aspx
Ma tieni a mente che avrai l'onere di tenere sincronizzate le due copie del db e crearti due modelli: uno per la scrittura e l'altro per la lettura.

In ultimo, puoi pur sempre decidere di cambiare provider e portare la tua applicazione su Windows Azure. Il vantaggio è che puoi scalare facilmente: la tua applicazione non sarà costretta a vivere in un solo server ma potrai farla girare su 2 o 3 istanze in corrispondenza delle tue campagne pubblicitarie, pagando solo ciò che effettivamente consumi. Qui trovi delle slides introduttive su Windows Azure, il servizio cloud di Microsoft.
http://www.slideshare.net/innovativesg/ms-cloud-day-introduction-to-windows-azure-platform-and-real-world-case-study
e invece qui hai il calcolatore dei prezzi, così puoi farti un'idea di quanto ti costerebbe, rispetto al tuo attuale gestore.
http://www.microsoft.com/windowsazure/pricing-calculator/

ciao,
Modificato da BrightSoul il 06 novembre 2011 19.07 -

Enjoy learning and just keep making
38 messaggi dal 20 ottobre 2009
Non sò più cosa pensare guarda, stà di fatto che accade solo quando il carico è alto e ci sono tanti accessi; stà di fatto che quando avevo il DB in hosting andava meglio di quando ho piazzato il DB sul Dedicato: CPU quasi al 100% con w3wp.exe e sqlserv.exe che praticamente se la spartivano. L'applicazione ha tante query sì ma non sono cose particolarmente colossali, nel senso che rientrano nella normalità diciamo; alcune stored procedure fanno qualche algoritmo di sorting per riordinare delle foto negli album degli utenti ma non c'è niente di particolarmente "HEAVY". C'è solo un ajax timer che fà ogni 15 secondi una richiesta dal client verso il server per controllare se ci sono delle info da aggiornare (vedi tipo facebook che quando qualcuno inserisce un post ti appare direttamente in tempo reale quasi nella bacheca facendo un refresh instantaneo diciamo..). Capisco per N utenti sono ulteriori richieste ogni 15 secondi che intensificano la cosa ma mi chiedo: come faccio a capire quale sogli devo tenere e quale no ? Alla fine c'è un server dedicato di mezzo che non è il top sul mercato ma sempre un pc usato solo e soltanto per quello con 4GB di RAM. Poi cmq tu dici che usare il DB su un altro server aumenta i tempi di latenza però scusa l'I/O su disco non migliora ? Un conto è se l'HD e la CPU devono soddisfare richieste HTTP e SQL Query un conto è se uno fà una cosa e l'altro un altra. Cioè spesso si consiglia di porre il DB su un altro Server, almeno così ho spesso sentito. Poi per I/O io comunque mi riferisco a quello su disco; alcuni errori che ho rilevato ad esempio erano dei timeout delle query che depongono a pensare che si tratti di un problema di risorse che sono troppo sovraccariche...adesso quali sono queste risorse in questo caso determinanti ? CPU o Hard Disk che non ce la fà ??

Dimenticavo: mettendo il DB sul Server Virtuale ho notato cmq un incremento della performance in termini di velocità non indifferenti...devo scoprire il motivo di questo problema altrimenti non posso più lavorare...non posso spendere soldi a potenziare e magari poi il problema persiste e non ho concluso niente..
Modificato da Sl4ck3r il 06 novembre 2011 19.22 -

Ci sono solo 10 categorie di persone al mondo: quelle che non conoscono il binario e quelle che lo conoscono.
38 messaggi dal 20 ottobre 2009
Ecco un tizio sul forum ufficiale di asp.net che ha riscontra problemi simili nelle medesime circostanze. Effettivamente si stupisce come mai così poche persone abbiano accusato tale problema...eppure è un mistero la mia storia è simile alla sua solo che a me non si verifica a seguito di un postback asincrono (leggendo alla fine, il tizio lo ha imputato alla presenza di un UpdatePanel...)

http://forums.asp.net/t/1645860.aspx/1/10

Ci sono solo 10 categorie di persone al mondo: quelle che non conoscono il binario e quelle che lo conoscono.
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

Sl4ck3r ha scritto:
Poi cmq tu dici che usare il DB su un altro server aumenta i tempi di latenza però scusa l'I/O su disco non migliora ? Un conto è se l'HD e la CPU devono soddisfare richieste HTTP e SQL Query un conto è se uno fà una cosa e l'altro un altra.


Certo, ma facendo delle misurazioni con il Performance Monitor, il Sql Profiler o altro strumento, dovresti cercare di capire se è effettivamente la soluzione migliore nel tuo caso. E capirlo non è una cosa immediata, ma puoi prepararti al meglio ai veri momenti di picco facendo delle "simulazioni di carico" con il tool WCat.
http://www.iis.net/community/default.aspx?tabid=34&g=6&i=1466

Sl4ck3r ha scritto:

adesso quali sono queste risorse in questo caso determinanti ? CPU o Hard Disk che non ce la fà ??

Non ho modo di saperlo... se ti suggerisco di misurare è perché non c'è una soluzione universalmente valida per ogni sistema e quindi bisogna "investigare".
Quello che mi viene in mente, se posizionassi il db su un'altra macchina, è che la tua applicazione *potrebbe* subire ripetutamente un certo overhead nella trasmissione dei dati in rete locale. Da quanto mi è sembrato di capire, la tua applicazione fa molte query (anche se "veloci") e deve soddisfare un certo numero di richieste al secondo, quindi questa tipologia di utilizzo potrebbe rendere più evidente il problema.

Sl4ck3r ha scritto:

Cioè spesso si consiglia di porre il DB su un altro Server, almeno così ho spesso sentito

E' vero ma non è un dogma. Quello diventa necessario quando hai più di un webserver che devono accedere ad una fonte di dati comune, oppure quando vuoi proteggere i dati dietro un firewall in modo che siano un po' più protetti se qualcuno dovesse bucarti il webserver.
E comunque tra le macchine c'è sempre un link Gigabit diretto, con Jumbo frames abilitati, mentre le tue macchine, correggimi se sbaglio, potrebbero non essere fisicamente neanche nella stessa stanza.

Nella scelta devi considerare anche il costo del mantenimento di un secondo server che si rivelerà effettivamente utile solo nei momenti di picco. Non sempre aumentare il proprio hardware ti dà il miglior rapporto benefici/costi.
Sl4ck3r ha scritto:

.non posso spendere soldi a potenziare e magari poi il problema persiste e non ho concluso niente..

Appunto :)


Sl4ck3r ha scritto:

Poi per I/O io comunque mi riferisco a quello su disco;

Sì sì, anch'io. Da questo punto di vista *potrebbe* essere più efficiente ed economico aggiungere al primo server un disco allo stato solido che userai solo per il database. Gli SSD sono enormemente più rapidi quando si tratta di accesso casuale ai dati. Qui trovi dei benchmark.

http://www.xlr8yourmac.com/IDE/SSD_vs_VelociRaptor_vs_Raptor/SSD_vs_VelociRaptor_Raptor.html


Queste, comunque, sono tutte idee campate in aria finché non hai delle misurazioni alla mano che ti suggeriscano quale strada intraprendere.

La prima cosa che farei per affrontare il problema è fare uno stress test per misurare il numero di richieste che il server può gestire e, al contempo, misurare i consumi di ram, cpu e disco nel periodo di tempo. Studiati i vari indicatori del performance monitor per avere un'idea su quali ti possano rilevare dove l'applicazione trascorre la maggior parte del tempo.
Hai anche quest'ottimo strumento gratuito che si chiama New Relic per misurare le performance (la versione Pro è in prova per 14 giorni). Guarda il video, il tizio fumettoso non sa proprio da dove iniziare :)
http://newrelic.com/why-new-relic/how-it-works

Poi, in base alle statistiche ottenute, andrei ad ottimizzare l'applicazione affinché faccia richieste al database il meno possibile. Questo, come già detto, puoi ottenerlo con i meccanismi di caching di asp.net, oppure infilando in uno stesso SqlCommand più comandi INSERT e UPDATE e query SELECT.
Poi, a ripetere lo stress test e annotare gli eventuali miglioramenti.
Vai avanti così finché continui a notare miglioramenti. Sperimenta anche varie impostazioni della connection string, specie quelle che riguardano il connection pooling.
http://msdn.microsoft.com/it-it/library/system.data.sqlclient.sqlconnection.connectionstring%28v=vs.80%29.aspx

Quando, nonostante le ottimizzazioni, non riesci a superare una certa soglia di richieste contemporanee allora potrai valutare hardware migliore o se invece affidarti ai servizi cloud per una maggiore scalabilità. A quel punto avrai anche maggiore consapevolezza su quali siano i "punti deboli" della macchina (es. non ha abbastanza RAM per accomodare la cache, oppure il disco non è abbastanza veloce, ecc..)

Nonostante non ti abbia dato la risposta che cercavi spero comunque di esserti stato utile per iniziare ad affrontare la questione.

ciao,
Modificato da BrightSoul il 07 novembre 2011 22.57 -

Enjoy learning and just keep making
38 messaggi dal 20 ottobre 2009
Sei stato gentile, utile e grandioso a dedicarmi il tuo tempo. GRAZIE. Faccio una cosa però adesso che forse non è il miglior compromesso in senso generale ma lo è nel mio caso specifico visto che non ho molto tempo da perdere: investo un centinaio di euro e prendo un server più potente in cui piazzare solo il DB per 1 mese e vedo l'andamento. Se non accade più nulla ho risolto e scoperto la causa. Posso buttare 100 euro che in caso positivo non sono buttate ma mi hanno consentito di comprendere dove stà il problema. Non sarà la soluzione migliore ma provo...non ho molto tempo da dedicare vediamo il DB su una macchina più degna e dedicata proprio allo scopo se continua a fare capricci perchè i problemi secondo me stanno proprio su esso in quanto gli errori più frequenti sono del tipo:

SqlCmd.CommandText = "SELECT COUNT(*) FROM Adv";

Data Conversion which almost always works good without problem:

try

{

SqlCmd.Connection.Open();

this._advCount = Convert.ToInt32(SqlCmd.ExecuteScalar());

}

finally

{

SqlCmd.Connection.Close();

}

ERROR:

Unable to cast object of type 'System.Guid' to type 'System.IConvertible'.

Nessuno passa un GUID come parametro al metodo ToInt32()...ma eppure sempre in modo random accade e inoltre:

Eccezione: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

StackTrace:
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket() at System.Data.SqlClient.TdsParserStateObject.ReadBuffer() at System.Data.SqlClient.TdsParserStateObject.ReadByte() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior) at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, String srcTable) at System.Web.UI.WebControls.SqlDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments) at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) at System.Web.UI.WebControls.DataBoundControl.PerformSelect() at System.Web.UI.WebControls.ListView.PerformSelect() at System.Web.UI.WebControls.BaseDataBoundControl.DataBind() at sogniamatoriali.it.UserControls.SViewersSearchPanel.PerformSearchOnUrlRequest()

E inoltre:

DataBinding: 'System.Data.DataRowView' does not contain a property with the name 'IsCertificated'.

Eccome se la colonna 'IsCertificated' ESISTE! Esiste eccome ma qui sembra non riuscire enumerarla a di seguito il relativo stacktrace:

StackTrace:
at System.Web.UI.DataBinder.GetPropertyValue(Object container, String propName) at System.Web.UI.DataBinder.Eval(Object container, String[] expressionParts) at System.Web.UI.DataBinder.Eval(Object container, String expression) at System.Web.UI.TemplateControl.Eval(String expression) at ASP.usercontrols_userslistviewtemplate_ascx.__DataBind__control2(Object sender, EventArgs e) at System.Web.UI.Control.OnDataBinding(EventArgs e) at System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) at System.Web.UI.Control.DataBind() at System.Web.UI.Control.DataBindChildren() at System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) at System.Web.UI.Control.DataBind() at System.Web.UI.Control.DataBindChildren() at System.Web.UI.Control.DataBind(Boolean raiseOnDataBinding) at System.Web.UI.Control.DataBind() at System.Web.UI.WebControls.ListView.CreateItemsWithoutGroups(ListViewPagedDataSource dataSource, Boolean dataBinding, InsertItemPosition insertPosition, ArrayList keyArray) at System.Web.UI.WebControls.ListView.CreateChildControls(IEnumerable dataSource, Boolean dataBinding) at System.Web.UI.WebControls.ListView.PerformDataBinding(IEnumerable data) at System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data) at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) at System.Web.UI.WebControls.DataBoundControl.PerformSelect() at System.Web.UI.WebControls.ListView.PerformSelect() at System.Web.UI.WebControls.BaseDataBoundControl.DataBind() at sogniamatoriali.it.UserControls.SViewersSearchPanel.PerformSearchOnUrlRequest()


Tutto questo mi porta a pensare: si tratta di qualcosa che ha a che vedere con il DB/Sql Server.

Sposto tutto su una macchina dedicata con una CPU con 8 core e 4 GB di RAM e 2 HD da 250 GB Ciascuno; su uno metto il .MDF e su l'altro il .LDF. Vediamo cosa succede, male che vada butto 100 euro ma è già un indizio anch'esso.

Cosa ne pensi ? Vuoi che ti tengo informato su l'andamento visto che è diventato, almeno per me, un caso quasi scientifico ? :D

Ci sono solo 10 categorie di persone al mondo: quelle che non conoscono il binario e quelle che lo conoscono.
11.886 messaggi dal 09 febbraio 2002
Contributi
Sl4ck3r ha scritto:

Unable to cast object of type 'System.Guid' to type 'System.IConvertible'.
ah, che stranezza!

Sl4ck3r ha scritto:
Cosa ne pensi ? Vuoi che ti tengo informato su l'andamento visto che è diventato, almeno per me, un caso quasi scientifico ? :D
sì, certo mi interessano i misteri inspiegabili :)

Fai una cosa, prova a disabilitare il connection pooling aggiungendo Pooling=false nella tua connectionstring.
E' vero che il pooling non dovrebbe essere mai disabilitato in produzione perché ciò limiterebbe le prestazioni, però per debuggare un caso insolito come questo temporaneamente puoi farlo.

Avrei dovuto chiedertelo prima ma... posta la connection string, ovviamente eliminando user e password, se ci sono. Per caso contiene Connection Reset=false?

ciao,
Modificato da BrightSoul il 09 novembre 2011 21.45 -

Enjoy learning and just keep making
38 messaggi dal 20 ottobre 2009
<add name="SADBdbConnectionString" connectionString="Data Source=xxx.xxx.xxx.xxx;Initial Catalog=DBName;Persist Security Info=True;User ID=xxxxxxx;Password=xxxxxx" providerName="System.Data.SqlClient" />

Ecco su la connectionstring.

Inoltre ti aggiorno su un nuovo e come al solito casuale errore dato proprio stamane (ciò ha del mistico proprio perchè appunto se faccio la richiesta http identica funziona tutto, non mi dà mai errore...e poi è un errore strano lato proprio sql server!):

The variable name '@UserID' has already been declared. Variable names must be unique within a query batch or stored procedure.

E' dichiarata solo 1 VOLTA nella sp di pertinenza !!!! Secondo me devo provare ad aggiornare sql server 2005 standard edition...! Non me lo spiego ! L'altra teoria è che il disco non legge bene in quanto il DB è su VPS e ovviamente è uno spazio condiviso quindi in base al carico non ce la fà..!

Ci sono solo 10 categorie di persone al mondo: quelle che non conoscono il binario e quelle che lo conoscono.

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.