Активные соединения Azure Sql превышают лимит пула соединений

Мы боремся с проблемой в производстве, когда время от времени производительность базы данных Azure SQL значительно ухудшается. Мы знаем, что у нас есть блокировки на одной из таблиц, но эти блокировки не являются взаимоблокировками, они длинные блокировки, и через час производительность возвращается к норме. Мы пытаемся найти все возможные сценарии того, как мы получаем эти длинные блокировки (каждый запрос очень быстрый, и все анализаторы производительности могут показать нам, что вызывает длинные блокировки). Причина этого вопроса заключается в следующем:

введите описание изображения здесь

Настройки пула соединений позволяют объединять только 200 подключений. И в большинстве случаев у нас около 10-20 открытых/объединенных соединений с базой данных. Затем внезапно начинается ряд активных соединений, и пул полностью взят. В то время как количество объединенных соединений остается ниже 200, мы видим, что число активных соединений с использованием sp_who2 достигает 1,5k-2k соединений (иногда 4k-5k).

Я построил ту же диаграмму, используя инструменты мониторинга Azure Portal. Он имеет различный период агрегации, но показывает ту же проблему: введите описание изображения здесь

используемая строка подключения:

Источник данных = [сервер].database.windows.net; начальный catalog = [база данных]; информация о безопасности сохраняется = True; пользователь ID = [пользователь], пароль = [пароль]; MultipleActiveResultSets = True; Соединение Timeout = 30; Max Pool Size = 200; Pooling = True; App = [AppName]

Как это возможно, учитывая ограничение пула соединений на 200 соединений?

ps: периодическая задача, длительный запрос или другой инструмент ничего не делают, мы проверили с sp_who2 все активные подключения к базе данных.

Ответ 1

[это скорее длинный комментарий, чем ответ]

У меня есть несколько хостов, подключенных к одной базе данных, но каждый хост имеет то же ограничение 200 соединений

Пул соединений: per (Connection String, AppDomain). На каждом сервере может быть несколько AppDomains. И каждый AppDomain будет иметь один пул соединений для каждой строки подключения. Итак, если у вас разные комбинации пользователей и паролей, они будут генерировать разные пулы соединений. Поэтому нет никакой реальной тайны, почему возможно иметь более 200 подключений.

Так почему вы получаете много соединений? Возможные причины:

Утечки соединений.

Если вы не удаляете DbContext или SqlConnection, соединение будет задерживаться на управляемой куче до тех пор, пока не будет завершено, и не будет доступно для повторного использования. Когда пул соединений достигнет своего предела, новый запрос на соединение будет ждать 30 секунд для того, чтобы соединение стало доступным, и сработало после этого.

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

select *
from sys.dm_exec_requests 

Обратите внимание, что статистика сеанса ожидания теперь активна на базе Azure SQL DB, поэтому гораздо проще увидеть блокировку и ожидания в реальном времени.

select *
from sys.dm_exec_session_wait_stats

Blocking.

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

select *
from sys.dm_exec_requests

Медленные запросы.

Если запросы просто говорили долгое время из-за доступности ресурсов (CPU, Disk, Log), вы могли это увидеть. Но это маловероятно, так как в это время ваше использование DTU низкое.

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

Ответ 2

Есть две вещи, которые вы можете проверить на объектах dbcontext, чтобы убедиться, что вы правильно их используете, и удалите объект, чтобы вернуть соединение с пулом соединений.

Сначала вы создаете dbcontext из кода. Проверьте, существует ли инструкция using вокруг каждой области создания объекта dbcontext. Что-то вроде:

using (var context = new xxxContext()) {
    ...
}

Это приведет к удалению контекста, когда он автоматически выходит из области.

Во-вторых, вы используете инъекцию зависимостей для инъекции объекта dbcontext. Убедитесь, что вы используете область действия:

services.AddScoped<xxxContext>(

Затем DI позаботится об утилизации ваших объектов контекста.

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

Ответ 3

Проблема может быть связана с " фрагментацией пула "

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

Фрагментация пула благодаря встроенной безопасности * Соединения объединяются в соответствии со строкой соединения и идентификацией пользователя. Поэтому, если вы используете обычную проверку подлинности или проверку подлинности Windows на веб-сайте и вход в систему с интегрированной защитой, вы получаете один пул на пользователя. Хотя это повышает производительность последующих запросов к базе данных для одного пользователя, этот пользователь не может использовать преимущества подключений других пользователей. Это также приводит как минимум к одному соединению на пользователя с сервером базы данных. Это побочный эффект конкретной архитектуры веб-приложений, который разработчики должны сопоставить с требованиями безопасности и аудита.

Источник: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling