Salve,

mi sono imbattuto in questo problema di performance piuttosto insolito ed anche molto subdolo e difficile da diagnosticare.

Se malauguratamente vi incappaste, questo post potrebbe farvi risparmiare parecchio tempo.

La ASP.NET web application in questione funzionava correttamente e senza problemi di sorta. Se non ché, lentamente ma inesorabilmente, le performance peggioravano di giorno in giorno fino a che l’applicazione risultava definitivamente bloccata e rispondeva Internal Server Error 500.

Riavviare IIS e persino riavviare la macchina non serviva a risolvere il problema.

D’altra parte, non vi erano segni di alta CPU o altri segnali che lasciassero pensare a stress da carico sulla macchina.

Dopo aver dato un’occhiata generale a vari contatori con il Performance Monitor siamo passati alla raccolta dei dump (generati in hang mode quando i problemi di performance erano evidenti).

Quest’ultima  ha subito portato alla luce diversi thread che impiegavano diversi secondi in stack analoghi al seguente (dallo stack sono stati rimossi i riferimenti al codice del cliente):

OS Thread Id: 0x108c (25)
ESP EIP
04d8e4fc 7c82ed54 [HelperMethodFrame_1OBJ: 04d8e4fc] System.Security.Cryptography.X509Certificates.X509Utils._QueryCertBlobType(Byte[])
04d8e570 795064dd System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[], System.Object, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
04d8e5a8 79505061 System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[])
04d8e5c0 7a54512f System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[])
04d8e5dc 06a9873c ---.---.---
04d8ef9c 661957c6 System.Web.UI.WebControls.Button.OnClick(System.EventArgs)
04d8efb0 661959bc System.Web.UI.WebControls.Button.RaisePostBackEvent(System.String)
04d8efc4 66195938 System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(System.String)
04d8efc8 661526c0 System.Web.UI.Page.RaisePostBackEvent(System.Web.UI.IPostBackEventHandler, System.String)
04d8efd0 6615260a System.Web.UI.Page.RaisePostBackEvent(System.Collections.Specialized.NameValueCollection)
04d8efe0 661560cf System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)
04d8f198 66154a1b System.Web.UI.Page.ProcessRequest(Boolean, Boolean)
04d8f1d0 66154967 System.Web.UI.Page.ProcessRequest()
04d8f208 66154887 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)
04d8f210 6615481a System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)
04d8f224 066b7a25 ASP.My_aspx.ProcessRequest(System.Web.HttpContext)
04d8f228 65ff27d4 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
04d8f25c 65fc15b5 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)
04d8f29c 65fd32e0 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)
04d8f2ec 65fc0225 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)
04d8f308 65fc550b System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)
04d8f33c 65fc5212 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)
04d8f348 65fc3587 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)
04d8f4f8 79f35ee8 [ContextTransitionFrame: 04d8f4f8]
04d8f548 79f35ee8 [GCFrame: 04d8f548]
04d8f6a0 79f35ee8 [ComMethodFrame: 04d8f6a0]

 

Dunque, molti thread dell’applicazione stavano lavorando con certificati di tipo X509, e tali thread stavano eseguendo molto lentamente.

All’apice dello stack si vede inoltre la funzione LoadCertificateFromBlo: dumpando la memoria col comando “dc” attorno agli indirizzi dei parametri in ingresso, abbiamo notato che per caricare il certificato la funzione fa utilizzo di file temporanei, salvati nella cartella Temp di sistema, con nomi tipo: C:\WINNT\TEMP\TmpE541.tmp

La cosa è stata successivamente confermata con dei log di Process Monitor che mostravano la creazione di decine di questi file.

Controllando la cartella Temp nella macchina del cliente abbiamo infine visto che conteneva decine di migliaia di questi file.

Cancellandoli e ripulendo la cartella il problema si è magicamente risolto.

Il mistero si è finalmente risolto quando abbiamo scoperto il seguente articolo:

On a Windows Server 2003-based client computer, the system does not delete a temporary file that is created when an application calls the "CryptQueryObject" function
http://support.microsoft.com/default.aspx?scid=kb;EN-US;931908

A causa di questo bug dunque il load dei certificati diventava sempre più lento e l’applicazione rallentava di conseguenza. Installare la Fix risolve il problema.

 

Alla prossima,

Stefano Pronti
Senior Support Engineer
EMEA IIS and Web Developer Support Team