2012-01-25 14 views
15

Widzę przerażający błąd "Upłynął limit czasu przed uzyskaniem połączenia z puli".Jak znaleźć nieszczelny uchwyt puli połączenia db?

Przeszukałem kod dla niezakrytych połączeń db, ale nie mogłem znaleźć żadnych.

Co chcę zrobić, to: następnym razem, gdy otrzymamy ten błąd, zrzutu systemu listę, które proc lub żądania HTTP trzymają wszystkie uchwyty, więc mogę dowiedzieć się, który kod jest przyczyną problemu.

Jeszcze lepiej byłoby zobaczyć, jak długo te uchwyty były trzymane, więc mogłem rozpoznać używane, ale niezamknięte połączenia.

Czy jest jakiś sposób to zrobić?

+0

Czy to możliwe, że masz więcej użytkowników niż połączeń w puli? –

+0

Czy przechowujesz odniesienia do połączenia w stanie sesji lub w innym miejscu, które ma okres ważności przekraczający jedno żądanie http? – Jan

+0

Nie, są otwarte i (przypuszczalnie) zamknięte na każde żądanie. – Jesse

Odpowiedz

5

Istnieje kilka dobrych linki do pula połączeń monitoringu. Wykonaj wyszukiwanie w Google dla "monitorowania puli połączeń .net".

Jeden artykuł, do którego odniosłem się po jakimś czasie, to Bill Vaughn's article (Uwaga: jest stary, ale nadal zawiera przydatne informacje). Ma trochę informacji o monitorowaniu pul połączeń, ale także wgląd w to, gdzie mogą występować wycieki.

Do monitorowania, sugeruje;

„Monitorowanie puli połączeń

Ok, więc otworzył połączenie i zamknął je i chcą wiedzieć, czy połączenie jest nadal w miejscu-marnieje w puli połączeń na materacu powietrza. Dobrze ., istnieje kilka sposobów, aby określić, ile połączenia są nadal w miejscu (nadal podłączony) i nawet co robią omówię kilka z nich tu i w mojej książce:

· Wykorzystanie SQL Profiler z SQLProfiler TSQL_Replay Szablon śledzenia. Dla tych, którzy znają Profiler, jest to łatwiejsze niż odpytywanie przy użyciu SP_WHO.

· Uruchom SP_WHO lub SP_WHO2, które zwracają informacje z tabeli sysprocesses dla wszystkich działających procesów pokazujących aktualny stan każdego procesu. Zasadniczo istnieje jeden proces serwera SPID na połączenie . Jeśli nazwałeś swoje połączenie, używając argumentu Nazwa aplikacji w łańcuchu połączenia, będzie to łatwe do znalezienia.

Skorzystaj z Monitora wydajności (PerfMon), aby monitorować pule i połączenia. Omówię to szczegółowo w następnej kolejności.

· Monitoruj liczniki wydajności w kodzie. Ta opcja umożliwia wyświetlenie lub po prostu monitorowanie kondycji puli połączeń i liczby nawiązanych połączeń. Omówię to w następnej sekcji tego artykułu."

Edit:

Jak zawsze, sprawdzić niektóre z other similar posts tutaj na SO

Druga Edycja:

Po potwierdzeniu, że połączenia nie są będąc odzyskiwany przez pulę, inną rzeczą, którą możesz spróbować, jest wykorzystanie zdarzenia StateChange w celu potwierdzenia, kiedy połączenia są otwierane i zamykane. Zmiany stanu na otwarte, a nie zamknięte, oznaczałoby to, że gdzieś są przecieki. Można również zarejestrować dane w zdarzeniu o stanie statystycznym wraz z sygnaturą czasową, a jeśli masz inne rejestrowanie aplikacji, możesz zacząć analizować pliki dziennika dla instancji, w których pojawiają się zmiany stanu zamkniętych na otwarte, z nie odpowiada otwarte na zamknięte. Zobacz this link, aby uzyskać więcej informacji na temat obsługi StateChangedEvent.

+0

Jeśli połączenia pozostają otwarte w puli, jak widzisz w programie SQL Profiler, gdy został osierocony? Wygląda na to, że potrzebna informacja nie znajduje się w bazie danych, ale w warstwie zarządzania pulą. – Jesse

+0

Nie mogę skomentować opcji SQL Profiler, ponieważ nie używałem tego do monitorowania pul połączeń. Dalsze informacje na temat rodzaju informacji, które można uzyskać z PerfMon i liczników wydajności (ostatnia para, o której mówi, można znaleźć pod adresem . w tych ** ** po ** otrzymasz "błąd przerażony" nie powie ci ** kiedy ** zostali osieroceni.Zapytałem dane za pomocą liczników wydajności głównie w celu potwierdzenia, że ​​liczba połączeń w używanie ciągle rośnie bez odzyskania, po potwierdzeniu musisz go polować –

+0

Hmm, niezupełnie srebrna kula, której szukałem, ale doceniam dokładne wyjaśnienie! – Jesse

0

Użyłem tego

http://www.simple-talk.com/sql/performance/how-to-identify-slow-running-queries-with-sql-profiler/

na znalezienie długo przed uruchomieniem procedur przechowywanych, mogę pracować z powrotem, a następnie znaleźć metodę, która o nazwie SP.

nie wiem, czy to będzie pomoc

+0

Problem (wydaje mi się), że mam nie jest związany z wolnymi uruchomieniami kwerend - jest to z kodem, który uruchamia zapytanie, a następnie nie zwalnia uchwytu db. – Jesse

13

Jeśli masz szczęście, że tworzenie/otwieranie połączenia jest scentralizowane, poniższa klasa powinna ułatwić wykrycie wycieków połączeń. Ciesz się :)

/// <summary> 
/// This class can help identify db connection leaks (connections that are not closed after use). 
/// Usage: 
/// connection = new SqlConnection(..); 
/// connection.Open() 
/// #if DEBUG 
/// new ConnectionLeakWatcher(connection); 
/// #endif 
/// That's it. Don't store a reference to the watcher. It will make itself available for garbage collection 
/// once it has fulfilled its purpose. Watch the visual studio debug output for details on potentially leaked connections. 
/// Note that a connection could possibly just be taking its time and may eventually be closed properly despite being flagged by this class. 
/// So take the output with a pinch of salt. 
/// </summary> 
public class ConnectionLeakWatcher : IDisposable 
{ 
    private readonly Timer _timer = null; 

    //Store reference to connection so we can unsubscribe from state change events 
    private SqlConnection _connection = null; 

    private static int _idCounter = 0; 
    private readonly int _connectionId = ++_idCounter; 

    public ConnectionLeakWatcher(SqlConnection connection) 
    { 
     _connection = connection; 
     StackTrace = Environment.StackTrace; 

     connection.StateChange += ConnectionOnStateChange; 
     System.Diagnostics.Debug.WriteLine("Connection opened " + _connectionId); 

     _timer = new Timer(x => 
     { 
      //The timeout expired without the connection being closed. Write to debug output the stack trace of the connection creation to assist in pinpointing the problem 
      System.Diagnostics.Debug.WriteLine("Suspected connection leak with origin: {0}{1}{0}Connection id: {2}", Environment.NewLine, StackTrace, _connectionId); 
      //That's it - we're done. Clean up by calling Dispose. 
      Dispose(); 
     }, null, 10000, Timeout.Infinite); 
    } 

    private void ConnectionOnStateChange(object sender, StateChangeEventArgs stateChangeEventArgs) 
    { 
     //Connection state changed. Was it closed? 
     if (stateChangeEventArgs.CurrentState == ConnectionState.Closed) 
     { 
      //The connection was closed within the timeout 
      System.Diagnostics.Debug.WriteLine("Connection closed " + _connectionId); 
      //That's it - we're done. Clean up by calling Dispose. 
      Dispose(); 
     } 
    } 

    public string StackTrace { get; set; } 

    #region Dispose 
    private bool _isDisposed = false; 

    public void Dispose() 
    { 
     if (_isDisposed) return; 

     _timer.Dispose(); 

     if (_connection != null) 
     { 
      _connection.StateChange -= ConnectionOnStateChange; 
      _connection = null; 
     } 

     _isDisposed = true; 
    } 

    ~ConnectionLeakWatcher() 
    { 
     Dispose(); 
    } 
    #endregion 
} 
+0

Pomogło nam to znaleźć połączenie, które zostało otwarte i nigdy nie było zamknięte Naprawdę fajna klasa :) Wielkie dzięki! – Challe

+0

Cudownie! Cieszę się, że to może być przydatne dla innych. – LOAS

Powiązane problemy