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