Как решить проблему пула соединений между ASP.NET и SQL Server?

Последние несколько дней мы видим это сообщение об ошибке на нашем сайте слишком много:

«Время ожидания истекло. Период ожидания истек до получения соединения из пула. Это могло произойти, потому что все соединения в пуле использовались и был достигнут максимальный размер пула».

Мы ничего не изменили в нашем коде в течение некоторого времени. Я пересмотрел код, чтобы проверить открытые соединения, которые не закрывались, но нашли все в порядке.

  • Как я могу решить это?

  • Нужно ли редактировать этот пул?

  • Как я могу отредактировать максимальное количество соединений в этом пуле?

  • Каково рекомендуемое значение для сайта с высоким трафиком?


Обновить:

Нужно ли что-то редактировать в IIS?

Обновить:

Я обнаружил, что число активных подключений составляет от 15 до 31, и обнаружил, что максимально допустимое количество подключений, настроенных на сервере SQL, превышает 3200, слишком много - 31, или я должен что-то редактировать в конфигурации ASP.NET. ?

22.03.2009 09:50:47
Максимальный размер пула по умолчанию равен 100, если я правильно помню. Большинство веб-сайтов не используют более 50 подключений под большой нагрузкой - это зависит от того, сколько времени потребуется для выполнения ваших запросов. Краткосрочное исправление в строке подключения: попробуйте установить более высокое значение в строках подключения: «Максимальный размер пула = ...»
splattne 22.03.2009 13:20:21
как много? например, 200?
Amr Elgarhy 22.03.2009 13:22:04
Я думаю, что вы должны действительно искать то, что вызывает проблему. Ваши запросы (или некоторые из них) выполняются очень долго?
splattne 22.03.2009 13:39:30
может быть, это и есть настоящая причина, запрос, выполнение которого занимает много времени, я буду искать в этом, спасибо
Amr Elgarhy 22.03.2009 13:49:10
Я надеюсь, что вы можете найти проблему. Предложение: если вы используете SQL Server, попробуйте «SQL Profiler» и ищите длинные запросы: sql-server-performance.com/articles/per/…
splattne 22.03.2009 13:58:10
21 ОТВЕТ
РЕШЕНИЕ

В большинстве случаев проблемы с пулами соединений связаны с «утечками соединений». Ваше приложение, вероятно, не закрывает свои подключения к базе данных правильно и последовательно. Когда вы оставляете соединения открытыми, они остаются заблокированными, пока сборщик мусора .NET не закроет их для вас, вызвав их Finalize()метод.

Вы хотите убедиться, что вы действительно закрываете соединение . Например, следующий код вызовет утечку соединения, если код между .Openи Closeвыдает исключение:

var connection = new SqlConnection(connectionString);
connection.Open();
// some code
connection.Close();                

Правильный путь будет такой:

var connection = new SqlConnection(ConnectionString);
try
{
     connection.Open();
     someCall (connection);
}
finally
{
     connection.Close();                
}

или

using (SqlConnection connection = new SqlConnection(connectionString))
{
     connection.Open();
     someCall(connection);
}

Когда ваша функция возвращает соединение из метода класса, убедитесь, что вы кэшируете его локально и вызываете его Closeметод. Вы потеряете соединение, используя этот код, например:

var command = new OleDbCommand(someUpdateQuery, getConnection());
result = command.ExecuteNonQuery();
connection().Close(); 

Соединение, возвращенное с первого звонка, getConnection()не закрывается. Вместо того, чтобы закрывать ваше соединение, эта строка создает новое и пытается закрыть его.

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


В этой статье « Почему переполнение пула соединений? » Из MSDN / SQL Magazine объясняется много деталей и предлагаются некоторые стратегии отладки:

  • Запустите sp_whoили sp_who2. Эти системные хранимые процедуры возвращают информацию из sysprocessesсистемной таблицы, которая показывает состояние и информацию обо всех рабочих процессах. Как правило, вы увидите один идентификатор процесса сервера (SPID) для каждого соединения. Если вы назвали свое соединение, используя аргумент «Имя приложения» в строке соединения, ваши рабочие соединения будет легко найти.
  • Используйте SQL Server Profiler с TSQL_Replayшаблоном SQLProfiler для отслеживания открытых соединений. Если вы знакомы с Profiler, этот метод проще, чем опрос с использованием sp_who.
  • Используйте системный монитор для мониторинга пулов и соединений. Я обсуждаю этот метод через минуту.
  • Мониторинг счетчиков производительности в коде. Вы можете отслеживать состояние вашего пула соединений и количество установленных соединений, используя процедуры извлечения счетчиков или используя новые элементы управления .NET PerformanceCounter.
213
25.09.2019 16:29:29
Небольшое исправление: сборщик мусора никогда не вызывает метод Dispose объекта, только его финализатор (если он есть). Финализатор может затем выполнить «запасной» вызов Dispose, если это необходимо, хотя я не уверен, что SqlConnection делает это.
LukeH 23.03.2009 13:38:06
Есть ли какое-либо снижение производительности, когда нам нужно установить максимальный размер пула 50, а у нас всего несколько пользователей.
mahesh sharma 9.07.2016 04:29:29

Вы можете указать минимальный и максимальный размер пула, указав MinPoolSize=xyzи / или MaxPoolSize=xyzв строке подключения. Эта причина проблемы могла быть другой вещью как бы то ни было.

5
22.03.2009 09:53:55
Какой рекомендуемый MaxPoolSize?
Amr Elgarhy 22.03.2009 11:22:13
Вероятно, лучший способ - не указывать его, если у вас нет особых требований и вы не знаете подходящий размер пула для вашего конкретного случая .
Mehrdad Afshari 22.03.2009 11:24:55
Примечание: я проверил, и я обнаружил, что активные соединения с моей базой данных около 22 живых, это слишком много?
Amr Elgarhy 22.03.2009 12:49:03
Я так не думаю. Я думаю, что размер пула по умолчанию составляет 100 соединений. Это зависит от загрузки каждого соединения в сети и на сервере SQL. Если те выполняют тяжелые запросы, это может вызвать проблемы. Кроме того, могут возникнуть проблемы с сетью при инициализации нового соединения, что может вызвать это исключение.
Mehrdad Afshari 22.03.2009 13:00:31

Если ваше использование не увеличилось, кажется маловероятным, что есть просто отставание в работе. ИМО, наиболее вероятным вариантом является то, что что-то использует соединения и не освобождает их быстро. Вы уверены, что используете usingво всех случаях? Или (через какой-либо механизм) освободить соединения?

13
22.03.2009 09:58:39

Проверяли ли вы DataReaders, которые не закрыты, и response.redirects перед закрытием соединения или устройства чтения данных. Соединения остаются открытыми, когда вы не закрываете их перед перенаправлением.

13
22.03.2009 10:05:28
+1 - Или функции, возвращающие DataReaders - Соединение никогда не закроется вне функции, которую вы их создали ...
splattne 22.03.2009 10:11:57
Если ваша функция возвращает SqlDataReader, вам лучше преобразовать ее в DataTable, чем увеличив максимальный размер пула
live-love 8.12.2014 20:12:36

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

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

5
22.03.2009 10:50:46
Мы используем LLBL, и веб-сайт работает с 2 лет, и только последние несколько дней начали действовать так.
Amr Elgarhy 22.03.2009 10:54:50

Мы также время от времени сталкиваемся с этой проблемой на нашем веб-сайте. В нашем случае виновником является наша статистика / индексы, устаревшие. Это приводит к тому, что ранее быстро выполняющийся запрос (в конечном итоге) замедляется и время ожидания истекает.

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

10
14.06.2009 22:51:42
Я думаю, что это объясняет, почему запрос может истечь, но я не думаю, что это объясняет, почему истекло время ожидания при попытке установить соединение.
DrGriff 23.06.2014 18:16:45
Возможно, при плохом индексе запросы занимают больше времени и одновременно используется больше соединений.
LosManos 29.07.2015 20:31:01
Работал у меня после обновления всей статистики с помощью sp_updatestats на БД: EXEC sp_updatestats;
boateng 26.10.2015 19:31:49

Если вы работаете над сложным унаследованным кодом, где простое использование (..) {..} невозможно - как я и сделал - вы можете проверить фрагмент кода, который я разместил в этом вопросе SO, чтобы определить стек вызовов при создании соединения, когда соединение потенциально утечка (не закрывается после заданного времени ожидания). Это позволяет довольно легко определить причину утечки.

2
23.05.2017 12:10:33

В основном это связано с тем, что соединение не было закрыто в приложении. Используйте «MinPoolSize» и «MaxPoolSize» в строке подключения.

3
31.07.2013 05:57:59

Использовать этот:

finally
{
    connection.Close();
    connection.Dispose();
    SqlConnection.ClearPool();
}
1
18.10.2017 10:50:18
Может быть, я упускаю суть SqlConnection.ClearPool, но разве это просто мешает вашему текущему соединению вернуться в пул соединений? Я думал, что идея пула соединений состояла в том, чтобы позволить более быстрые соединения. Надежное освобождение соединения из пула каждый раз, когда оно завершается, означает, что НОВОЕ соединение нужно будет создавать КАЖДЫЙ РАЗ, вместо того, чтобы извлекать запасное соединение из пула? Пожалуйста, объясните, как и почему эта техника полезна.
Dib 6.04.2016 15:35:45

В моем случае я не закрывал объект DataReader.

        using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*"))
        using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString))
            {
            dbCmd.CommandType = CommandType.StoredProcedure;

            //Add parametres
            dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID;
.....
.....
            dbCmd.Connection.Open();
            var dr = dbCmd.ExecuteReader(); //created a Data reader here
            dr.Close();    //gotta close the data reader
            //dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method.
            }
3
24.08.2015 15:31:37

После установки .NET Framework v4.6.1 наши подключения к удаленной базе данных сразу же начали истекать из- за этого изменения .

Для исправления просто добавьте параметр TransparentNetworkIPResolutionв строку подключения и установите для него значение false :

Server = MyServerName; Database = MyDatabase; Trusted_Connection = True; TransparentNetworkIPResolution = False

35
10.05.2018 11:49:58
В этом случае возникает проблема «Время ожидания истекло до получения подключения из пула». Исправило ли это исправление в строке подключения, или это была отдельная проблема с подтверждением связи?
FBryant87 24.05.2018 09:52:02
Из того, что я помню, это было точно такое же сообщение об ошибке, как в вопросе. Это произошло сразу после обновления до .NET Framework v4.6.1.
ajbeaven 24.05.2018 10:26:37
Это также относится ко мне, исправил это для меня в службе приложений, которую я запускал в Azure, подключился к базе данных SQL Azure. Я использовал Dapper и правильно удалял соединения, но все еще получал сообщение об ошибке «истекло время ожидания до получения соединения из пула». Но не более, так что спасибо @ajbeaven
Steve Kennaird 4.06.2019 08:21:34

Не создавайте SQL-соединение слишком много раз. Откройте одно или два соединения и используйте их для всех последующих операций sql.

Кажется, что даже при Disposeподключении возникает исключение.

2
13.06.2016 10:39:08

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

 Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) {
                          sqlconnection1.Open();
                          SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();
                          sqlcommand1.CommandText = raiserror (‘This is a fake exception’, 17,1)”;
                          sqlcommand1.ExecuteNonQuery();  //this throws a SqlException every time it is called.
                          sqlconnection1.Close(); //Still never gets called.
              } // Here sqlconnection1.Dispose is _guaranteed_

https://blogs.msdn.microsoft.com/angelsb/2004/08/25/connection-pooling-and-the-timeout-expired-exception-faq/

0
15.08.2016 13:14:35

С этой проблемой я сталкивался раньше. В итоге возникла проблема с брандмауэром. Я просто добавил правило в брандмауэр. Мне пришлось открыть порт, 1433чтобы сервер SQL мог подключиться к серверу.

0
5.10.2017 20:37:50

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

 String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')";
    //,'" + d1 + "','" + f1 + "','" + g1 + "'

    SqlConnection con = new SqlConnection(mycon);
    con.Open();
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = query;
    cmd.Connection = con;
    cmd.ExecuteNonQuery();
    **con.Close();**

Вы хотите закрыть соединение каждый раз. До этого я не использовал тесную связь из-за этого я получил ошибку. После добавления оператора close у меня вышла эта ошибка

1
18.11.2017 11:41:30

Вы также можете попробовать это для решения проблемы тайм-аута:

Если вы не добавили httpRuntime в веб-конфигурацию, добавьте это в <system.web>тег

<sytem.web>
     <httpRuntime maxRequestLength="20000" executionTimeout="999999"/>
</system.web>

а также

Измените строку подключения следующим образом;

 <add name="connstring" connectionString="Data Source=DSourceName;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=50000;Pooling=True;" providerName="System.Data.SqlClient" />

При последнем использовании

    try
    {...} 
    catch
    {...} 
    finaly
    {
     connection.close();
    }
5
2.01.2018 14:37:14

В дополнение к размещенным решениям ....

Имея дело с 1000 страницами устаревшего кода, каждая из которых вызывает общий GetRS несколько раз, вот еще один способ решить эту проблему:

В существующей общей DLL мы добавили опцию CommandBehavior.CloseConnection :

    static public IDataReader GetRS(String Sql)
    {
        SqlConnection dbconn = new SqlConnection(DB.GetDBConn());
        dbconn.Open();
        SqlCommand cmd = new SqlCommand(Sql, dbconn);
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);   
    }

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

    IDataReader rs = CommonDLL.GetRS("select * from table");
    while (rs.Read())
    {
        // do something
    }
    rs.Close();   // this also closes the connection
2
31.05.2018 05:32:46

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

Чтобы воспроизвести проблему, попробуйте это:

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}
0
2.04.2020 15:47:22

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

select st.text,
    es.*, 
    ec.*
from sys.dm_exec_sessions as es
    inner join sys.dm_exec_connections as ec on es.session_id = ec.session_id
    cross apply sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
where es.program_name = '<your app name here>'
2
18.02.2019 11:37:15

Да, есть способ изменить конфигурацию. Если вы находитесь на выделенном сервере и вам просто нужно больше соединений SQL, вы можете обновить записи «max pool size» в обеих строках соединения, следуя этим инструкциям:

  1. Войдите в свой сервер с помощью удаленного рабочего стола
  2. Откройте Мой компьютер (Windows - E) и перейдите в C: \ inetpub \ vhosts [домен] \ httpdocs
  3. Дважды щелкните файл web.config. Это может быть просто указано как веб, если структура файла настроена на скрытие расширений. Это откроет Visual Basic или аналогичный редактор.
  4. Найдите строки подключения, они будут похожи на примеры ниже:

    "add name =" SiteSqlServer "connectionString =" server = (local); database = dbname; uid = dbuser; pwd = dbpassword; pooling = true; время жизни соединения = 120; максимальный размер пула = 25; ""

5. Измените максимальный размер пула = X на требуемый размер пула.

  1. Сохраните и закройте файл web.config.
0
15.11.2019 06:37:38

Убедитесь, что вы установили правильные настройки для пула соединений. Это очень важно, как я объяснил в следующей статье: https://medium.com/@dewanwaqas/configurations-that-significantly-improves-your-app-performance-built-using-sql-server-and-net- ed044e53b60 Вы заметите существенное улучшение производительности вашего приложения, если будете им следовать.

0
18.03.2020 18:56:05