2014-11-17 31 views
5

Moja aplikacja do tworzenia aplikacji ASP.NET 4.0 napotyka na ponowne problemy, które powodują, że witryna przestaje reagować z powodu błędów przekroczenia limitu czasu.Limit czasu wygasł. Limit czasu upłynął przed uzyskaniem połączenia z puli. Enterprise Library

Oto krótki przegląd aplikacji. Aplikacja znajduje się na 3 serwerach; serwer WWW, serwer aplikacji i serwer bazy danych SQL Server 2008. Wszystkie serwery działają w systemie Windows Server 2008. Serwer sieciowy znajduje się w domenie publicznej. Serwer aplikacji znajduje się w strefie DMZ z otwartą komunikacją między serwerem sieci Web a portami 80 i 443 za pośrednictwem WCF. Serwer DB znajduje się w domenie prywatnej z otwartą komunikacją z serwerem aplikacji przez port 1433. Aplikacja jest już od jakiegoś czasu produkowana i tylko doświadcza tych problemów często od zeszłego tygodnia. Nie było zmian w kodzie, a dostawca hostingu stwierdził, że ostatnio nie było żadnych zmian na serwerze.

Na serwerze internetowym w aplikacji wystąpił błąd opisany poniżej (Błąd 1). Rozwiązaniem szybkiej korekty jest zrestartowanie procesu serwera aplikacji IIS, jednak jest to obecnie powtarzający się problem i powoduje poważne zakłócenia dla właścicieli firm.

DAL aplikacji używa Enterprise Library v4.1 do otwierania połączeń z bazą danych. Dodałem 2 fragmenty kodu odpowiedzialnego za inicjowanie połączeń (kod 1 i kod 2). Ta metoda jest powtarzana w różnych innych metodach. Czy jest możliwe, że metoda ExecuteReader nie zamyka prawidłowo połączenia? Nie ma żadnej zmiany metody, która pozwala mi określić ConnectionBehavior, aby zamknąć połączenie.

Przeprowadziliśmy analizę profilu SQL i stwierdziliśmy, że nie ma trwałych otwartych połączeń z bazą danych.

Podczas badania problemu ktoś zasugerował, że biblioteka korporacyjna może mieć błąd, w którym połączenia nie są prawidłowo usuwane, jednak nie zostało to zweryfikowane w poście. Jak mogę określić przyczynę problemu? Lub jaki byłby właściwy sposób rozwiązania problemu? Mogłabym zwiększyć wielkość puli, ale wydaje się, że byłaby to tymczasowe rozwiązanie.

Błąd 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) 

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

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

Wygląda na to, że problem nie dotyczy żadnej z metod, do których odwoływały się błędy w programie ASP.NET. Wyrzucili wyjątek, ponieważ do czasu, w którym zostały osiągnięte, problem (wyczerpana pula połączeń) już wystąpił, a wyjątek zostałby zgłoszony w przypadku każdej metody postępowania, która otwiera nowe połączenie.

Po przeanalizowaniu całego kodu w warstwie dostępu do danych zidentyfikowałem kilka metod rouge, które nie wykorzystywały poprawnie instrukcji using, pozostawiając otwarte połączenia w puli do kumulacji. Po wyizolowaniu metod i zastosowaniu monitorów wydajności do obserwowania NumberOfPooledConnections, potwierdziłem, że te metody były obwiniane.

Poprawka polegała na zawijaniu metod rouge w odpowiednich instrukcjach użycia.

Jedną z metod powodujących problem:

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

Odpowiedz

2

widzę wiele działań dzieje raz Reader jest otwarty. Jeśli istnieją wyjątki związane z funkcją zależną, takie jak: myNav.Categories = GetCategoriesCollectionFromReader (reader); może otworzyć czytnik. Bezpieczna strona wyłącznie zamknij czytnik. tak:

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

Należy także oko na serwerze SQL:

SELECT DB_NAME (dbid), COUNT (dbid) loginame od sys.sysprocesses gdzie dbid> 0 GROUP BY dbid , loginname

+0

Rajiv, proszę o odpowiedź. Zanim zobowiązuję się do wprowadzenia zmian w całej aplikacji, chcę najpierw potwierdzić, że to jest problem. Poprosiłem mojego hosta, aby dostarczył mi informacje o bieżącym numerze połączonych połączeń w momencie wystąpienia wyjątków, a także zrzut pamięci procesu roboczego usług IIS. W tym momencie nie jestem nawet pewien, czy kod, który napisałem, jest winowajcą, więc priorytet nr 1 identyfikuje problem. Jakieś dalsze sugestie, jak to zrobić? Również polecenie SQL, które wysłałeś, zawsze zwraca 1 dla COUNT (dbid). –

1

Jednym ze sposobów debugowania jest dodanie liczników wydajności do śledzenia/rejestrowania/obsługi wyjątków. NumberOfActiveConnectionPoolGroups, NumberOfActiveConnectionPools i NumberOfPooledConnections są prawdopodobnie wartościami licznika potrzebnymi do debugowania problemu. MSDN Link

+0

Spróbuję. Dziękuję Ci. –