Пул подключений к SQL Server в Microsoft.Data.SqlClient

Пул подключений в Microsoft.Data.SqlClient повторно использует аутентифицированные физические соединения. SqlConnection.Open Или OpenAsync проверяет пул на наличие полезного соединения. Close, Dispose, или DisposeAsync сбрасывает и возвращает его. Этот подход позволяет избежать сетевого подключения, аутентификации и настройки сессии для каждой операции.

Пулинг по умолчанию включён. Используйте следующую схему применения:

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

using var command = new SqlCommand(sql, connection);
await command.ExecuteNonQueryAsync(cancellationToken);

Открывайте как можно позже, освобождайте как можно раньше и позвольте пулу управлять физическими соединениями. Не оставляйте SqlConnection открытым глобально.

Понимайте ключи пула

Соединение может быть использовано повторно только из соответствующего пула. Ключ пула включает не только сервер назначения.

Input Поведение бассейна
Строка соединения Текст должен совпадать точно. Различия в порядке ключевых слов создают отдельные пулы, даже если эффективные настройки равнозначны.
Встроенная проверка подлинности Windows Идентичность Windows — часть ключа. Одна и та же строка, используемая с разными идентификаторами, создаёт разные пулы.
SqlCredential Экземпляр объекта является частью ключа. Отдельные экземпляры создают отдельные пулы, даже если они содержат одно и то же имя пользователя и пароль.
SqlConnection.AccessToken Значение токена доступа является частью ключа. Замена строк токенов может создавать новые пулы и оставлять соединения аутентифицированными со старыми токенами в существующих пулах.
SqlConnection.AccessTokenCallback Обратный отклик — часть ключа. Используйте один и тот же экземпляр функции обратного вызова для соединений, которые должны использовать общий пул. Возвращённое значение токена — это не ключ пула.
Пользовательский SSPI-провайдер контекста В конфигурации соединения участвует экземпляр провайдера. Используйте один экземпляр провайдера для соединений, которые должны объединяться.
Окружающая транзакция Подключения, включённые в транзакцию, используют отдельные секции для каждой транзакции внутри соответствующего пула.

База данных, режим аутентификации, опции шифрования, имя приложения, опции пула и все остальные значения строка подключения вносят вклад через точную строку.

Создайте одну каноническую строку подключения и используйте её повторно. Избегайте значений для каждого запроса в Application Name, Workstation ID или других ключевых словах.

Выбирайте API токенов, которые можно объединять

Для токенов доступа Microsoft Entra ID используйте режим аутентификации, предоставляемый Microsoft.Data.SqlClient, или стабильный AccessTokenCallback.

AccessTokenCallback появился в Microsoft.Data.SqlClient 5.2. Драйвер вызывает его, когда нужен токен, и может запросить обновлённый токен для повторно используемого пула. Обеспечьте детерминированность обратного вызова для параметров аутентификации, предоставляемых драйвером, и повторно используйте тот же экземпляр делегата.

Когда код напрямую задаёт AccessToken:

  • Строка токена становится частью ключа пула.
  • Приложение управляет сроком действия токена и его обновлением.
  • Физическое соединение, объединённое в пул, может существовать дольше, чем токен, использованный для его создания.
  • Вызовите ClearPool после замены просроченного токена, если этот пул больше нельзя безопасно использовать.

Не создавайте новый callback lambda или объект учетных данных для каждого запроса. Различия идентичности объектов могут фрагментировать пулы.

В Microsoft.Data.SqlClient 7.0 добавлен SspiContextProvider для настраиваемого согласования Kerberos или NTLM. Считайте провайдера конфигурацией соединения уровня приложения, а не состоянием на уровне отдельного запроса.

Размер каждого пула

Эти параметры строки подключения управляют одним пулом:

Keyword По умолчанию Effect
Pooling true Включает или отключает пулинг.
Min Pool Size 0 Устанавливает минимальное количество физических соединений, которые пул сохраняет после его создания.
Max Pool Size 100 Устанавливает максимальное количество физических соединений в пуле.
Connect Timeout 15 секунд Устанавливает, как долго Open ожидает, если нет подходящего соединения.
Load Balance Timeout 0 секунды Отбрасывает соединение при возврате в пул, если его возраст превышает заданное значение. Connection Lifetime — это псевдоним.

Пул создаёт соединения по мере роста спроса, пока их число не достигнет Max Pool Size. Когда все соединения используются, позже открываются и ждут возвращения соединения. Если ожидание превышает Connect Timeout, операция открытия завершается неудачей.

Не повышайте Max Pool Size до проверки:

  • Каждое соединение и каждый считыватель размещены на каждом пути.
  • Команды и транзакции завершаются оперативно.
  • Нагрузка на запросы не заблокирована и не перегружена.
  • Лимит подключений к базе данных позволяет обслуживать Max Pool Size, умноженное на количество пулов в каждом экземпляре приложения.

Положительный Min Pool Size вариант поддерживает открытые соединения в периоды простоя. Используйте его только если измерения оправдывают тёплые соединения. Обычно это плохо сочетается с масштабированием до нуля, бессерверной автоматической приостановкой и облачными архитектурами с кратковременным увеличением ресурсов.

При стандартном Load Balance Timeout=0режиме периодическая очистка обычно удаляет неиспользуемые соединения выше Min Pool Size примерно через четыре-восемь минут, либо пул удаляет их, когда обнаруживает разрыв серверного соединения. Рассматривайте этот интервал как поведение реализации, а не гарантию простоя на каждом соединении. Пул не отправляет валидационный запрос перед каждым заказом, потому что этот круговой маршрут убирает большую часть преимущества пула.

Обработка периодов блокировки аутентификации

После тайм-аута аутентификации или другого сбоя аутентификации пул может перейти в состояние блокировки. В течение этого периода соответствующие попытки открытия повторно вызывают исходное исключение, не выполняя ещё одну попытку аутентификации.

Первый период блокировки — пять секунд. После очередной неудачи период удваивается до одной минуты.

Pool Blocking Period Контролирует это поведение:

Ценность Behavior
Auto Включает блокировку для обычных конечных точек SQL Server и отключает её для распознанных суффиксов конечных точек Azure SQL. Vanity DNS-имя может не получать поведение Azure.
AlwaysBlock Включает период блокировки для каждой конечной точки.
NeverBlock Отключает период блокировки.

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

Период блокировки отделен от настраиваемой логики повторных попыток. Провайдер повторных попыток, который открывает тот же пул в период блокировки, получает кэшированное исключение.

Управление сроком действия соединения и очисткой

Пул автоматически очищает затронутый пул, когда распознаёт фатальную ошибку, например, отказ. Пул закрывает холостые соединения и отбрасывает проверенные соединения при их возвращении.

Используйте API очистки для известной конфигурации или границы учетных данных:

  • ClearPool очищает пул, связанный с одной SqlConnection конфигурацией.
  • ClearAllPoolsочищает все Microsoft. Data.SqlClient пулы в домене процесса или приложения.

Бассейн закрывает холостые соединения в очищенном бассейне. Пул отмечает соединения, которые сейчас используются, поэтому при возврате их удаляется.

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

Load Balance Timeout обеспечивает постепенную смену кадров по возрасту. Используйте это, когда при развёртывании или для кластерной службы нужно, чтобы старые физические соединения постепенно завершались. Убедитесь, что выбранное значение не вызывает чрезмерных жёстких соединений.

Общие сведения о транзакциях

При использовании Enlist=true соединение, открытое внутри System.Transactions.Transaction.Current, по умолчанию автоматически включается в эту транзакцию.

Когда соединение, включённое в транзакцию, закрывается, пул помещает его в отдельный раздел, предназначенный для этой транзакции. Позже открытая по той же транзакции может использовать её повторно. Физическое соединение не возвращается в общий пул до завершения транзакции.

Длительные или незавершённые неявные транзакции могут:

  • Не включайте физические соединения в общий пул.
  • Потребляйте ёмкость пула после закрытия логического соединения.
  • Сохраняйте серверные блокировки и состояние транзакции активными.

Держите транзакции ограниченными, выполняйте их явно и контролируйте соединения со стазисом. Устанавливайте Enlist=false только тогда, когда соединение должно оставаться вне окружающей транзакции.

Предотвращение фрагментации пула

Фрагментация пулов создаёт множество небольших бассейнов вместо нескольких многоразовых пулов. Распространенные причины:

  • Порядок ключевых слов между строками соединения или различия в псевдонимах.
  • Одна строка подключения для каждого клиента, пользователя, запроса или базы данных.
  • Интегрированная аутентификация под многими идентичностями Windows.
  • Новые экземпляры SqlCredential, обработчика обратного вызова токена доступа или поставщика SSPI для каждого запроса.
  • Прямые токены доступа, которые меняются при каждом обновлении.
  • Имена приложений высокой кардинальности или идентификаторы рабочих станций.

Нормализуйте строки подключения с SqlConnectionStringBuilder и централизуйте создание подключений.

Если приложение намеренно подключается к множеству баз данных или идентичностей, включите полученное количество пулов в планирование мощности. Не запускайте USE с ненадёжным именем базы данных, чтобы обрушить пулы. Изоляция базы данных, разрешения, состояние сеанса и поведение при сбросе пула должны быть явно определены.

Учет ролей приложений и состояния сессии

Пул сбрасывает повторно используемое состояние сессии SQL Server перед назначением физического соединения на другое логическое соединение. Код приложения должен по-прежнему задавать требуемое состояние сессии внутри своей рабочей единицы.

Активированные роли sp_setapprole приложений SQL Server нельзя безопасно сбросить для обычного пула. Предпочтительнее использовать пользователей базы данных, автономных пользователей, роли, безопасность на уровне строк или другую схему авторизации. Если роль приложения неизбежна, используйте задокументированный шаблон отката на основе файлов cookie или отключите пул соединений на этом изолированном пути после тестирования.

Устраняйте считыватели, завершайте или откатывайте транзакции, и не оставляйте команды в работе при закрытии соединения. Не полагайтесь на то, что временные таблицы или другое состояние сеанса сохранятся при переходе между логическими соединениями.

Используйте облачные паттерны пулирования

Для Служба приложений Azure, Функции Azure, контейнеров, Kubernetes и других горизонтально масштабируемых узлов:

  • Рассчитайте возможные соединения баз данных между всеми экземплярами, процессами, ключами пула и репликами.
  • Используйте управляемую идентификацию или функцию обратного вызова для токена доступа вместо ротации строк токенов в объектах подключения.
  • Оставьте Min Pool Size=0, если только измеримое требование к холодному запуску не обосновывает сохранение сеансов.
  • Следует ожидать, что новый экземпляр будет запущен с пустым пулом.
  • Сохраняйте одинаковые строки соединения для разных экземпляров, обслуживающих одну и ту же нагрузку.
  • Ограничьте количество попыток подключения и повторных попыток, чтобы избежать синхронных всплесков попыток входа при аварийном переключении или горизонтальном масштабировании.
  • Установите MultiSubnetFailover=true для Azure SQL и других поддерживаемых конечных точек TCP с несколькими адресами.

Пулы соединений локальны для процесса подачи заявки. Они не используются между экземплярами приложений, контейнерами или хостами.

Диагностика поведения пула

Используйте диагностические счетчики SqlClient для наблюдения:

  • Жёсткие соединения и отключения, которые представляют собой физические соединения серверов.
  • Мягкие соединения и отключения, которые обозначают выезд и возврат в пуле.
  • Активные и бесплатные объединённые соединения.
  • Активные группы и бассейны.
  • Стазисные соединения.
  • Восстановленные соединения, где код приложения не устранял логическое соединение.

Сопоставьте счётчики клиентов с сессиями, ожиданиями, блокировками и лимитами ресурсов SQL Server. Тайм-аут пула может означать утечку соединения, замедление запросов, заблокированные транзакции, чрезмерную параллельность, фрагментацию пула или ограничение пропускной способности базы данных.

Используйте трассировку источников событий для целевых трассировок пулера. Трассировка подробна. Включите его для ограниченного диагностического окна и защитите все захваченные метаданные соединения.

Контрольный список для продакшена

  • Оставьте пул включённым.
  • Используйте одну каноническую строку подключения для каждой рабочей нагрузки и базы данных.
  • Избавляйтесь от соединений, команд, считывателей и транзакций на каждом пути.
  • Повторно используйте учетные данные, обратные вызовы токенов и экземпляры провайдера SSPI.
  • Установите ограниченные тайм-ауты для соединения и команд.
  • Определите общий бюджет соединения для каждого экземпляра приложения.
  • Следите за жёсткими соединениями, количеством пулов, бесплатными соединениями, стазисом и тайм-аутами.
  • Очищайте пулы только для границы учетных данных, токена или конфигурации, которую провайдер не может обнаружить, либо когда результаты диагностики подтверждают, что сохраняются устаревшие соединения.
  • Перед вводом в эксплуатацию протестируйте поведение системы при горизонтальном масштабировании, аварийном переключении и обновлении учетных данных.