Несколько одновременных тайм-аутов SQL-соединения в многопоточной службе Windows - PullRequest
25 голосов
/ 04 мая 2011

У меня есть многопоточная служба Windows, которую я разработал для VS 2010 (.NET 4.0), которая может иметь от нескольких до нескольких десятков потоков, каждый из которых получает данные с медленного сервера через Интернет, а затем использует локальную базу данных.чтобы записать эти данные (чтобы процесс был связан с Интернетом, а не с ЛВС или ЦП).

С некоторой регулярностью я получаю флуд / шквал / пакет следующих ошибок одновременно из нескольких потоков:

System.Data.SqlClient.SqlException (0x80131904): истекло время ожидания.Время ожидания истекло до завершения операции или сервер не отвечает.

Стек вызовов для этой ошибки обычно:

в System.Data.ProviderBase,)

в System.Data.SqlClient.SqlConnection.Open ()

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

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

using (SqlConnection con = new SqlConnection(GetConnectionString()))
using (SqlCommand cmd = new SqlCommand("AddGdsMonitorLogEntry", con))
{
    cmd.CommandType = CommandType.StoredProcedure;

    /* setting cmd.Parameters [snipped] */

    // We have been getting some timeouts writing to the log; wait a little longer than the default.
    cmd.CommandTimeout *= 4;

    con.Open();

    cmd.ExecuteNonQuery();
}

Большое спасибо!

РЕДАКТИРОВАТЬ

Учитывая комментарии об этом, происходящие в зеркальных средах, я действительно должен отметить, что рассматриваемая база данныхотражается.В SSMS он помечен как «Основной, Синхронизированный», в режиме «Высокая безопасность без автоматического перехода на другой ресурс (синхронный)».

РЕДАКТИРОВАТЬ 5/26/11

Яничего не видеть в журналах SQL Server, чтобы указать на какие-либо проблемы.(У меня нет доступа к средству просмотра событий Windows на этом сервере, но я попросил кого-нибудь найти меня.)

Ответы [ 5 ]

15 голосов
/ 27 мая 2011

По сообщению в блоге MSDN , только что созданному сегодня (ура для Google!):

Microsoft подтвердила, что это проблема в текущем выпуске ADO.NET. Эта проблема будет исправлена ​​в версии ADO.NET, поставляется с Visual Studio 2011.

Тем временем мы просим использовать следующие обходные пути:

  1. Увеличьте время ожидания строки соединения до 150 с. Это даст первой попытке достаточно времени для соединения (150 * .08 = 12 сек)

  2. Добавьте MinPool Size = 20 в строке подключения. Это всегда будет поддерживать не менее 20 соединений в пуле, и будет меньше шансов на создание нового соединения, что уменьшит вероятность этой ошибки.

  3. Улучшение производительности сети. Обновите драйверы NIC до последней версии прошивки. Мы наблюдали задержку в сети, когда ваша сетевая карта несовместима с некоторыми настройками Scalable Networking Pack. Если вы используете Windows Vista с пакетом обновления 1 (SP1) или более поздней версии, вы можете также отключить автоматическую настройку окна приема. Если у вас включено объединение сетевых карт, было бы неплохо отключить его.

Сам пост является интересным чтением, рассказывающим об алгоритме повторных попыток соединения TCP / IP. И слава всем людям, которые сказали: «Эй, похоже, это связано с зеркалированием ...»! И обратите внимание на комментарий о том, что это «из-за медленного ответа от SQL Server или из-за сетевых задержек».

UGH !!!

Спасибо всем, кто написал. Теперь мы все должны запросить исправление для .NET Framework (или какого-либо другого механизма исправления ADO.NET), поэтому нам не нужно ждать (и покупать) Visual Studio 11 ...

7 голосов
/ 15 мая 2011

Время ожидания соединения отличается от времени ожидания команды.Тайм-аут команды относится к ситуации, когда у вас установлено соединение, но по некоторым внутренним причинам сервер не может вернуть результаты в течение требуемого времени.Время ожидания команды по умолчанию составляет 30 секунд.http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx

Попробуйте указать время ожидания подключения в строке подключения.Значение по умолчанию составляет 15 секунд, что может быть причиной проблемы, которую вы видите.Вы также можете указать время ожидания подключения в коде: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx

1 голос
/ 20 мая 2011

Я получаю это время от времени на этом старом сервере баз данных, который у нас есть (нам уже 10 лет). Когда это случается, хотя это происходит потому, что что-то постоянно напирает эту вещь соединениями / запросами. Я предполагаю, что вы обнаружите, что, когда это происходит, сервер базы данных находится под нагрузкой (или большое количество соединений или что-то в этом роде) В любом случае, по моему опыту, если вы можете оптимизировать код, оптимизировать базу данных, получить более мощный сервер базы данных и т. д. все помогает. Еще одна вещь, которую вы можете сделать, как предлагает Петр, - просто увеличить время ожидания соединения. Я бы все-таки прошел и оптимизировал некоторые вещи (это должно помочь в долгосрочной перспективе).

0 голосов
/ 20 мая 2011

Оптимизация запросов, выполняемых на удаленном сервере, всегда поможет. Время каждого запроса и искать долгосрочные. Если вы просто выполняете чтение, используйте подсказку (NOLOCK) в инструкциях SELECT. Это было спасение для меня. Просто прочтите его, чтобы убедиться, что он подходит для вашего приложения. Если у вас есть доступ к удаленной базе данных, убедитесь, что индексы не фрагментированы . Это приведет к значительному замедлению выполнения запроса. Убедитесь, что индексы перестроены / реорганизованы как часть плана обслуживания SQL. При необходимости добавьте новые индексы.

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

0 голосов
/ 16 мая 2011

Мне удалось несколько надежно воспроизвести эту проблему. У меня есть служба, которая, когда запрашивается задание на обработку, запускает обработку в новом домене / потоке приложений. Этот поток выполнит от 10 до 16 запросов к базе данных одновременно. Когда я запускаю 30 из этих заданий одно за другим, случайное одно или два задания завершаются с ошибкой тайм-аута.

Я изменил строку подключения, чтобы отключить пул соединений с пулами = false, а затем ошибка изменилась на следующую. Это генерируется 3 или 4 раза внутри статистического исключения, так как соединения происходят внутри Parallel.For

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParserStateObject.ReadNetworkPacket()
   at System.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(Boolean encrypt, Boolean trustServerCert, Boolean& marsCapable)
   at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity)
   at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, SqlConnection owningObject)
   at System.Data.SqlClient.SqlInternalConnectionTds.LoginWithFailover(Boolean useFailoverHost, ServerInfo primaryServerInfo, String failoverHost, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, TimeoutTimer timeout)
   at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, TimeoutTimer timeout, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup)
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.ExecuteQuery(PtQuery query, ValueStore`1 store, String readerDescription) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 326
   at Tps.PowerTools.CoreEngine.V5.DataAccess.DataContext.<StockHistoricalData>b__15(PtQuery query) in C:\SourceCode\Tps.PowerToolsV1\Trunk\Libraries\CoreEngine\CoreEngine.V5\DataAccess\DataContext.cs:line 302
   at System.Threading.Tasks.Parallel.<>c__DisplayClass32`2.<PartitionerForEachWorker>b__30()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object )
...