Активные соединения 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