2014-11-17 27 views
5

La mia applicazione di produzione ASP.NET 4.0 sta riscontrando problemi ricorrenti che causano la mancata risposta del sito a causa di errori di timeout.Timeout scaduto. Il periodo di timeout è trascorso prima di ottenere una connessione dal pool. Enterprise Library

Ecco una breve panoramica dell'applicazione. L'applicazione risiede su 3 server; un server Web, un server app e un server DB con SQL Server 2008. Tutti i server sono in esecuzione su Windows Server 2008. Il server Web è di dominio pubblico. Il server delle app risiede in una DMZ con comunicazione aperta tra il server Web sulle porte 80 e 443 tramite WCF. Il server DB risiede in un dominio privato con comunicazione aperta al server dell'app sulla porta 1433. L'applicazione è in produzione da un po 'di tempo e presenta solo questi problemi frequentemente la scorsa settimana. Non sono state apportate modifiche al codice e il provider di hosting ha dichiarato che non sono state apportate modifiche al server eseguite di recente.

Sul server Web, l'applicazione presenta l'errore indicato di seguito (Errore 1). La soluzione rapida consiste nel riavviare il processo IIS del server delle app, tuttavia si tratta di un problema ricorrente che causa gravi interruzioni ai proprietari di attività.

Il DAL dell'applicazione utilizza Enterprise Library v4.1 per aprire le connessioni al database. Ho incluso 2 snippet di codice che sono responsabili dell'avvio delle chiamate (codice 1 e codice 2). Questo metodo viene ripetuto in vari altri metodi. È possibile che il metodo ExecuteReader non stia chiudendo correttamente la connessione? Non esiste alcuna sovrascrittura del metodo che mi consente di specificare ConnectionBehavior per chiudere la connessione.

Abbiamo eseguito un'analisi del profilo SQL e determinato che non ci sono persistenti connessioni aperte al DB.

Durante la ricerca del problema, qualcuno ha suggerito che Enterprise Library potrebbe avere un bug in cui le connessioni non sono state smaltite correttamente, tuttavia questo non è stato verificato sul post. Come posso determinare la causa del problema? O quale sarebbe la linea di condotta appropriata per porre rimedio al problema? Potrei aumentare la dimensione del pool, tuttavia sembra che sarebbe solo una soluzione temporanea.

di errore 1:

***System.ServiceModel.FaultException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) at System.Data.SqlClient.SqlConnection.Open() at Microsoft.Practices.EnterpriseLibrary.Data.Database.GetNewOpenConnection() at Microsoft.Practices.EnterpriseLibrary.Data.Database.GetOpenConnection(Boolean disposeInnerConnection) at Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader(DbCommand command) at Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader(String storedProcedureName, Object[] parameterValues) at CityStoreDAL.NavigationProvider.GetNavigator(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreDAL\NavigationProvider.cs:line 41 at CityStoreBLL.Navigation.GetNavigator(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreBLL\Navigation.cs:line 15 at CityStoreService.CityStoreService.GetNavigator(Int32 navigato rID) in c:\TFS\CityStore\DEV\SRC\CityStoreService\Navigation.cs:line 21 at SyncInvokeGetNavigator(Object , Object[] , Object[]) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)*** 
Generated: Wed, 12 Nov 2014 19:40:22 GMT 

System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.ServiceModel.FaultException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) 
    at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) 
    at System.Data.SqlClient.SqlConnection.Open() 
    at Microsoft.Practices.EnterpriseLibrary.Data.Database.GetNewOpenConnection() 
    at Microsoft.Practices.EnterpriseLibrary.Data.Database.GetOpenConnection(Boolean disposeInnerConnection) 
    at Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader(DbCommand command) 
    at Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader(String storedProcedureName, Object[] parameterValues) 
    at CityStoreDAL.NavigationProvider.GetNavigator(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreDAL\NavigationProvider.cs:line 41 
    at CityStoreBLL.Navigation.GetNavigator(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreBLL\Navigation.cs:line 15 
    at CityStoreService.CityStoreService.GetNavigator(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreService\Navigation.cs:line 21 
    at SyncInvokeGetNavigator(Object , Object[] , Object[]) 
    at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) 
    at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) 
    at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) 
    at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) 

Server stack trace: 
    at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) 
    at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) 
    at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) 
    at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) 

Exception rethrown at [0]: 
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
    at CityStoreWeb.CityStoreServiceReference.INavigation.GetNavigator(Int32 navigatorID) 
    at CityStoreWeb.Product.<>c__DisplayClass1.<BindCategoryMenuAndInfo>b__0(INavigation proxy) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Product.aspx.cs:line 73 
    at CityStoreWeb.Common.Service'1.Use(UseServiceDelegate'1 codeBlock) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Common\Utils.cs:line 243 
    at CityStoreWeb.Product.BindCategoryMenuAndInfo(Int32 navigatorID) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Product.aspx.cs:line 71 
    at CityStoreWeb.Product.SetupPage(Int32 navigatorID, Int32 categoryID, Int32 productID) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Product.aspx.cs:line 64 
    at CityStoreWeb.Product.Page_Load(Object sender, EventArgs e) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Product.aspx.cs:line 37 
    at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) 
    at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) 
    at System.Web.UI.Control.OnLoad(EventArgs e) 
    at CityStoreWeb.Common.BasePage.OnLoad(EventArgs e) in c:\TFS\CityStore\DEV\SRC\CityStoreWeb\Common\BasePage.cs:line 26 
    at System.Web.UI.Control.LoadRecursive() 
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 
    --- End of inner exception stack trace --- 
    at System.Web.UI.Page.HandleError(Exception e) 
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 
    at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 
    at System.Web.UI.Page.ProcessRequest() 
    at System.Web.UI.Page.ProcessRequest(HttpContext context) 
    at ASP.product_aspx.ProcessRequest(HttpContext context) 
    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

Codice 1:

public static NavigatorEntity GetNavigator(int navigatorID) 
{ 
     Database db = DatabaseFactory.CreateDatabase(); 
     object[] spParams; 
     spParams = new object[1]; 
     spParams[0] = navigatorID; 
     using (IDataReader reader = db.ExecuteReader("GetNavigator", spParams)) 
     { 
      if (reader == null)k 
      { 
       throw new ArgumentNullException("reader"); 
      } 
      NavigatorEntity myNav = null; 
      if (reader.Read()) 
      { 
       myNav = GetNavigatorEntityFromReader(reader); 
      } 

      if (myNav != null) 
      { 
       reader.NextResult(); 
       myNav.Categories = GetCategoriesCollectionFromReader(reader); 

       reader.NextResult(); 
       myNav.RecommendedProducts = 
        ProductProvider.GetRecommendedProductCollectionFromReader(reader, false); 
      } 

      return myNav; 
     } 
    } 

Codice 2:

public static List<NavigatorEntity> GetNavigatorsAll() 
{ 
    Database db = DatabaseFactory.CreateDatabase(); 

    using (IDataReader myReader = db.ExecuteReader("GetNavigatorsAll")) 
    { 
     return GetNavigatorCollectionFromReader(myReader); 
    } 
} 

private static List<NavigatorEntity> GetNavigatorCollectionFromReader(IDataReader reader) 
{ 
    List<NavigatorEntity> navigators = new List<NavigatorEntity>(); 
    while (reader.Read()) 
    { 
     navigators.Add(GetNavigatorEntityFromReader(reader)); 
    } 
    return navigators; 
} 

UPDATE:

Apparentemente, il problema non era con nessuno dei metodi a cui si faceva riferimento negli errori ASP.NET. Hanno lanciato un'eccezione perché quando sono stati raggiunti, il problema (pool di connessioni esaurito) si era già verificato e l'eccezione veniva generata su qualsiasi metodo di procedimento che apre una nuova connessione.

Dopo aver analizzato tutto il codice nel livello di accesso ai dati, ho identificato alcuni metodi rouge che non utilizzavano l'istruzione using in modo appropriato, lasciando quindi accumulare connessioni aperte nel pool. Dopo aver isolato i metodi e usato i monitor delle prestazioni per osservare NumberOfPooledConnections, ho confermato che questi metodi erano da incolpare.

La correzione era di avvolgere i metodi rouge nelle istruzioni using appropriate.

Uno dei metodi che causano il problema:

public static List<TaxCodeEntity> CMSGetTaxCodes() 
{ 
    Database db = DatabaseFactory.CreateDatabase(); 
    return GetTaxCodeCollectionFromReader(db.ExecuteReader("CMS_GetTaxCodes"));    
} 

Fix:

public static List<TaxCodeEntity> CMSGetTaxCodes() 
{ 
    Database db = DatabaseFactory.CreateDatabase(); 
    using (DbCommand dbCmd = db.GetStoredProcCommand("CMS_GetTaxCodes")) 
    { 
     using (IDataReader myReader = db.ExecuteReader(dbCmd)) 
     { 
      return GetTaxCodeCollectionFromReader(myReader); 
     }  
    } 
} 

risposta

2

posso vedere molte azioni accadendo una volta Reader è aperto. Eventuali eccezioni generate dalla funzione dipendente come: myNav.Categories = GetCategoriesCollectionFromReader (reader); può tenere il lettore aperto. Il lato sicuro chiude esclusivamente il lettore. in questo modo:

public static NavigatorEntity GetNavigator(int navigatorID) 
    { 
     Database db = DatabaseFactory.CreateDatabase(); 
     object[] spParams; 
     spParams = new object[1]; 
     spParams[0] = navigatorID; 
     using (IDataReader reader = db.ExecuteReader("GetNavigator", spParams)) 
     { 
      try 
      { 
       if (reader == null) 
       { 
        throw new ArgumentNullException("reader"); 
       } 
       NavigatorEntity myNav = null; 
       if (reader.Read()) 
       { 
        myNav = GetNavigatorEntityFromReader(reader); 
       } 

       if (myNav != null) 
       { 
        reader.NextResult(); 
        myNav.Categories = GetCategoriesCollectionFromReader(reader); 

        reader.NextResult(); 
        myNav.RecommendedProducts = 
         ProductProvider.GetRecommendedProductCollectionFromReader(reader, false); 
       } 

       return myNav; 
      } 
      catch 
      { 
      } 
      finally 
      { 
       reader.Close(); 
      } 
     } 
    } 

Anche tenere d'occhio sul server SQL:

SELEZIONA DB_NAME (dbid), COUNT (dbid), loginame da sys.sysprocesses dove dbid> 0 GROUP BY dbid , loginame

+0

Rajiv, thx per la vostra risposta. Prima di impegnarmi a fare le modifiche in tutta l'applicazione, voglio prima confermare che è il problema. Ho richiesto al mio ospite di fornirmi informazioni sul numero corrente di connessioni in pool al momento delle eccezioni, nonché su un dump della memoria del processo di lavoro IIS. A questo punto, non sono nemmeno sicuro che il codice che ho postato sia il colpevole, quindi la priorità # 1 sta identificando il problema. Altri suggerimenti su come fare per fare questo? Inoltre, il comando SQL che hai pubblicato restituisce sempre 1 per COUNT (dbid). –

1

Un modo per eseguire il debug consiste nell'aggiungere contatori delle prestazioni per tracciare/registrare/gestire eccezioni. NumberOfActiveConnectionPoolGroups, NumberOfActiveConnectionPools e NumberOfPooledConnections sono probabilmente i valori del contatore necessari per eseguire il debug del problema. MSDN Link

+0

Farò un tentativo. Grazie. –

Problemi correlati