2014-11-17 12 views
5

Meine ASP.NET 4.0-Produktionsanwendung tritt erneut auftretende Probleme auf, die dazu führen, dass die Site aufgrund von Zeitüberschreitungsfehlern nicht mehr reagiert.Zeitlimit abgelaufen. Die Zeitüberschreitung ist abgelaufen, bevor eine Verbindung vom Pool erhalten wurde. Enterprise-Bibliothek

Hier ist ein kurzer Überblick über die Anwendung. Die Anwendung befindet sich auf 3 Servern. ein Webserver, ein Anwendungsserver und ein Datenbankserver mit SQL Server 2008. Alle Server werden unter Windows Server 2008 ausgeführt. Der Webserver befindet sich in der öffentlichen Domäne. Der App-Server befindet sich in einer DMZ mit offener Kommunikation zwischen dem Webserver über die Ports 80 und 443 über WCF. Der DB-Server befindet sich in einer privaten Domäne mit offener Kommunikation mit dem Anwendungsserver über Port 1433. Die Anwendung wurde bereits seit einiger Zeit produktiv eingesetzt und tritt erst seit letzter Woche häufig auf. Es gab keine Code-Änderungen und der Hosting-Provider sagt, dass es in letzter Zeit keine Änderungen am Server gab.

Auf dem Webserver tritt die Anwendung der unten aufgeführten Fehler (Fehler 1). Die schnelle Lösung besteht darin, den IIS-Prozess des Anwendungsservers neu zu starten. Dies ist jedoch ein wiederkehrendes Problem und führt zu größeren Unterbrechungen der Geschäftsinhaber.

Die DAL der Anwendung verwendet Enterprise Library v4.1, um Verbindungen zur Datenbank zu öffnen. Ich habe 2 Codeschnipsel eingefügt, die für das Einleiten der Anrufe verantwortlich sind (Code 1 und Code 2). Diese Methode wird in verschiedenen anderen Methoden wiederholt. Ist es möglich, dass die ExecuteReader-Methode die Verbindung nicht ordnungsgemäß schließt? Es gibt keine Überschreibung der Methode, mit der ich ConnectionBehavior zum Schließen der Verbindung angeben kann.

Wir haben eine SQL-Profilanalyse durchgeführt und festgestellt, dass keine offenen Verbindungen zur Datenbank bestehen.

Bei der Untersuchung des Problems schlug jemand vor, dass die Enterprise Library möglicherweise einen Fehler enthält, bei dem Verbindungen nicht ordnungsgemäß entsorgt werden, dies wurde jedoch auf dem Post nicht verifiziert. Wie kann ich die Ursache des Problems ermitteln? Oder was wäre die geeignete Vorgehensweise, um das Problem zu beheben? Ich könnte die Poolgröße erhöhen, aber das scheint nur eine temporäre Lösung zu sein.

Fehler 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) 

Code 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; 
     } 
    } 

Code 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:

Offenbar war das Problem nicht mit einer der Methoden, die in den ASP.NET-Fehlern verwiesen wurden. Sie haben eine Ausnahme ausgelöst, weil zu dem Zeitpunkt, zu dem sie erreicht wurden, das Problem (erschöpfter Verbindungspool) bereits aufgetreten war und die Ausnahme bei jeder weiterführenden Methode ausgelöst würde, die eine neue Verbindung öffnet.

Nachdem ich den gesamten Code in der Datenzugriffsebene analysiert hatte, identifizierte ich einige Rouge-Methoden, die die using-Anweisung nicht in geeigneter Weise verwendeten, wodurch offene Verbindungen im Pool akkumuliert wurden. Nachdem ich die Methoden isoliert und Performance-Monitore zur Beobachtung der NumberOfPooledConnections verwendet hatte, bestätigte ich, dass diese Methoden schuld waren.

Die Lösung bestand darin, die Rouge-Methoden in die entsprechenden using-Anweisungen einzufügen.

Eine der Methoden, die das Problem verursacht:

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); 
     }  
    } 
} 

Antwort

2

Ich kann viele Aktionen sehen geschieht einmal Reader geöffnet ist. Wenn Ausnahmen bei abhängigen Funktionen ausgelöst werden: myNav.Categories = GetCategoriesCollectionFromReader (reader); kann den Leser offen halten. Sichere Seite schließt ausschließlich den Leser. dies wie:

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(); 
      } 
     } 
    } 

auch ein Auge auf Ihren SQL-Server halten:

SELECT DB_NAME (dbid), COUNT (dbid), loginame von sys.sysprocesses wo dbid> 0 GROUP BY Dbid , loginame

+0

Rajiv, thx für Ihre Antwort. Bevor ich mich dazu verpflichte, die Änderungen in der gesamten Anwendung vorzunehmen, möchte ich zunächst bestätigen, dass dies das Problem ist. Ich habe meinen Host gebeten, mir Informationen über die aktuelle Anzahl der gepoolten Verbindungen zum Zeitpunkt der Ausnahmen sowie einen Arbeitsspeicherabzug des IIS-Arbeitsprozesses zur Verfügung zu stellen. An diesem Punkt bin ich mir nicht einmal sicher, ob der Code, den ich gepostet habe, der Täter ist, daher ist die Priorität Nr. 1 die Identifizierung des Problems. Noch mehr Vorschläge, wie man das macht? Der von Ihnen gepostete SQL-Befehl gibt immer 1 für COUNT (dbid) zurück. –

1

Eine Möglichkeit zum Debuggen besteht darin, Leistungsindikatoren zur Ablaufverfolgung/Protokoll-/Ausnahmebehandlung hinzuzufügen. NumberOfActiveConnectionPoolGroups, NumberOfActiveConnectionPools und NumberOfPooledConnections sind wahrscheinlich die Zählerwerte, die Sie zum Debuggen des Problems benötigen. MSDN Link

+0

Ich werde es versuchen. Vielen Dank. –