Как найти утечку пула подключений пула db?

Я вижу страшный "Истекший период ожидания до получения соединения из пула".

Я искал код для любых закрытых подключений db, но не смог найти.

Что я хочу сделать, так это следующее: в следующий раз, когда мы получим эту ошибку, у вас есть системный дамп, список которых обрабатывает или обрабатывает HTTP-запросы, поэтому я могу выяснить, какой код вызывает проблему.

Еще лучше было бы посмотреть, как долго эти ручки были сохранены, поэтому я мог заметить используемые, но незакрытые соединения.

Есть ли способ сделать это?

Ответ 1

Есть несколько хороших ссылок для мониторинга пулов соединений. Сделайте поиск google для "мониторинга пула соединений .net".

Одна статья, на которую я ссылался некоторое время назад, была статья Билла Вона (обратите внимание, что она устарела, но все еще содержит полезную информацию). В нем есть информация о мониторинге пулов подключений, но некоторые большие сведения о том, где могут возникать утечки.

Для мониторинга он предлагает:

"Контроль пула соединений

Хорошо, поэтому вы открыли соединение и закрыли его, и хотите узнать, соединение все еще на месте - томятся в пуле соединений на надувной матрас. Ну, есть несколько способов определить, сколько соединения все еще на месте (все еще подключены) и даже то, что они делаем. Я обсуждаю некоторые из них здесь и в моей книге:

. Используйте SQL Profiler с SQLProfiler TSQL_Replay шаблон для трассировки. Для тех, кто знаком с Profiler, это проще, чем опрос с использованием SP_WHO.

. Запустите SP_WHO или SP_WHO2, которые возвращают информацию из таблица sysprocesses во всех рабочих процессах, показывающая текущий статус каждого процесса. Как правило, один SPID-серверный процесс за подключение. Если вы назвали свое соединение, используя имя приложения аргумент в строке соединения, его легко найти.

· Используйте монитор производительности (PerfMon) для мониторинга пулов и соединения. Я подробно расскажу об этом ниже.

· Мониторинг счетчиков производительности в коде. Этот вариант позволяет вы можете отобразить или просто контролировать работоспособность пула соединений и количество установленных соединений. Я обсуждаю это в последующий раздел в этой статье."

Изменить:

Как всегда, ознакомьтесь с некоторыми другими аналогичными сообщениями здесь на SO

Второе редактирование:

Как только вы подтвердите, что соединения не будут восстановлены пулом, вы можете попытаться использовать событие StateChange, чтобы подтвердить, когда соединения открываются и закрываются. Если вы обнаружите, что открываются гораздо больше изменений состояния, чем закрыты, это указывает на то, что где-то есть утечки. Затем вы также можете регистрировать данные в событии statechanged вместе с меткой времени, и если у вас есть другой журнал в вашем приложении, вы можете начать анализировать файлы журнала для случаев, когда, как представляется, изменения состояния закрыты для открытия, с нет соответствующего открытого для закрытия. См. эту ссылку для получения дополнительной информации о том, как обращаться с StateChangedEvent.

Ответ 2

Если вам повезло, что создание/открытие соединений централизовано, то следующий класс должен упростить обнаружение утечек соединений. Наслаждайтесь:)

/// <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 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 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 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
}