Mon problème concerne un serveur Web aspx.net 4.0 bloquant sous une charge accrue. En bloquant je veux dire que la demande est envoyée par le client mais la réponse est renvoyée après ~ 45 secondes. Ceci est reproductible dans l'environnement de développement et de production. Ces 45 secondes semblent être constantes et j'ai mesuré à la fois sur le client et dans la page aspx entre l'appel du constructeur() et void Render(HtmlTextWriter writer)
. J'utilise à la fois plusieurs SqlDataSources et des contrôles personnalisés en utilisant 6 SqlCommand.BeginExecuteReader(...)
au total sur une page. Je peux éliminer le problème si je désactive les contrôles avec le motif BeginExecuteReader
/EndExecuteReader
. Je suppose donc que l'un des appels BeginExecute est bloqué jusqu'à ce qu'un thread soit disponible dans le ThreadPool.threadpool famine
imprimer des messages de débogage et reconnu un modèle où toujours un tas de messages de sortie de fil est imprimé juste befor la demande bloquée est renvoyée:
Le fil « GetMolFileAsync » (0x1ba4) est sorti avec le code 0 (0x0).
Le thread 'GetMolFileAsync' (0x27d0) s'est terminé avec le code 0 (0x0).
Le thread '' (0x23c) s'est terminé avec le code 0 (0x0).
Le thread 'GetCompoundDepositionInfo' (0x1e88) s'est terminé avec le code 0 (0x0).
Le thread 'GetMolFileAsync' (0x2758) s'est terminé avec le code 0 (0x0).
0x43 27/07/2012 15:09:42 45 ==>fil bloqué a pris 45 secondes
0x5F 27/07/2012 15:10:27 0 ==>comportement normal, traité dans certains miliseconds
...
Ceci est la méthode pour lancer une requête à la base de données
public static IAsyncResult GetCompoundDepositionInfoAsync(object sender, EventArgs e, AsyncCallback callback, object state)
{
GetCompoundVersionInfoAsyncParameters parameters = (GetCompoundVersionInfoAsyncParameters)state;
IAsyncResult res = null;
parameters.cmd = new System.Data.SqlClient.SqlCommand("www.GetCompoundDepositionInfo", new System.Data.SqlClient.SqlConnection(parameters.connectionstring));
parameters.cmd.CommandType = System.Data.CommandType.StoredProcedure;
parameters.cmd.Parameters.AddWithValue("@CompoundID", parameters.CompoundID);
try
{
parameters.cmd.Connection.Open();
res = parameters.cmd.BeginExecuteReader(callback, parameters, System.Data.CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
if (parameters.cmd.Connection.State == System.Data.ConnectionState.Open)
{
parameters.cmd.Connection.Close();
}
throw new Exception("Exception in calling GetCompoundDepositionInfoAsync()", ex);
}
return res;
}
c'est la fonction de rappel
public void GetCompoundDepositionInfoCallback(IAsyncResult result)
{
gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters param = (gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters)result.AsyncState;
System.Threading.Thread.CurrentThread.Name = "GetCompoundDepositionInfo";
using(System.Data.SqlClient.SqlCommand command = param.cmd)
using(System.Data.SqlClient.SqlDataReader reader = command.EndExecuteReader(result))
{
try
{
if (reader.Read())
{
lblDeposited.Text = string.Concat("at ", reader.GetDateTime(0).ToShortDateString(), " by ", reader.GetString(1));
}
}
finally
{
if (reader != null)
{
reader.Close();
command.Connection.Close();
}
}
}
}
et c'est le code pour les coller ensemble ...
Page.RegisterAsyncTask(new PageAsyncTask(
new BeginEventHandler(gmdTools.GmdCompound.GetCompoundLastChangeInfoAsync)
, new EndEventHandler(GetCompoundLastChangeInfoCallback)
, new EndEventHandler(GetCompoundInfoAsyncTimeout)
, new gmdTools.GmdCompound.GetCompoundVersionInfoAsyncParameters()
{
connectionstring = Properties.Settings.Default.GmdConnectionString,
CompoundID = CompoundId,
}, true
));
Comme je l'ai déjà passé des heures à regarder ce code je serais reconnaissants des commentaires.
MISE À JOUR Ce 45 secondes sont motivées par le défaut Page.AsyncTimeout
et peuvent être modifiés à 10 secondes en utilisant les Async="true" AsyncTimeout="10"
déclarations. Bien que j'aie beaucoup amélioré les performances globales du site en ajoutant des index appropriés, très souvent le client doit attendre ce laps de temps avant que le serveur n'envoie la réponse. Dans ce cas, aucun gestionnaire AsyncTimeout
n'est appelé. Je suppose que la page enregistre toutes les opérations asynchrones mais ne reconnaît finalement pas que certaines des opérations asynchrones ont réussi et attend donc AsyncTimeout secondes avant de rendre la page. Des commentaires à ce sujet?
Ressemble de blocage sur la base de données. Je vous suggère de surveiller l'activité de la base de données/utiliser SQL Profiler pour savoir ce qui se passe dans la base de données. – Polyfun
Êtes-vous sûr que les requêtes de base de données ne sont pas le coupable ici? Le fait que le moment est toujours le même pour un certain nombre de clients suggère que le facteur commun peut être la base de données. – dash
@ShellShock: Merci d'avoir commenté ma question! Compte tenu de votre expérience, quels événements dans le profileur SQL suggérez-vous de suivre ce blocage? – jahu