Как вы справляетесь с ошибками транспортного уровня в SqlConnection?
Время от времени в приложении.NET большого объема вы можете увидеть это исключение при попытке выполнить запрос:
System.Data.SqlClient.SqlException: произошла ошибка транспортного уровня при отправке запроса на сервер.
Согласно моим исследованиям, это то, что "просто случается", и мало что можно сделать, чтобы предотвратить это. Это не происходит в результате неправильного запроса и, как правило, не может быть продублировано. Он просто появляется, может быть, раз в несколько дней в загруженной системе OLTP, когда по какой-то причине TCP-соединение с базой данных ухудшается.
Я вынужден обнаружить эту ошибку, проанализировав сообщение об исключении и затем повторив всю операцию с нуля, чтобы включить использование нового соединения. Ничего из этого не красиво.
У кого-нибудь есть альтернативные решения?
11 ответов
Я разместил ответ на другой вопрос по другой теме, который может быть использован здесь. Этот ответ включал SMB-соединения, а не SQL. Однако это было идентично в том, что это включало низкоуровневую транспортную ошибку.
Мы обнаружили, что в ситуации большой нагрузки удаленному серверу было довольно легко рассчитывать время ожидания соединений на уровне TCP просто потому, что сервер был занят. Частично причина была в том, что по умолчанию TCP будет повторно передавать данные в Windows, что не соответствует нашей ситуации.
Взгляните на настройки реестра для настройки TCP/IP в Windows. В частности, вы хотите посмотреть на TcpMaxDataRetransmissions и, возможно, TcpMaxConnectRetransmissions. По умолчанию они равны 5 и 2 соответственно, попробуйте немного увеличить их в клиентской системе и продублируйте ситуацию загрузки.
Не сходи с ума! TCP удваивает время ожидания при каждой последующей повторной передаче, поэтому поведение времени ожидания для плохих соединений может оказаться экспоненциальным, если вы увеличите их слишком много. Насколько я помню, повышение TcpMaxDataRetransmissions до 6 или 7 решило нашу проблему в подавляющем большинстве случаев.
Это сообщение в блоге Майкла Аспенгрена объясняет сообщение об ошибке "Ошибка транспортного уровня при отправке запроса на сервер".
Чтобы ответить на ваш оригинальный вопрос:
Более элегантный способ обнаружения этой конкретной ошибки, без разбора сообщения об ошибке, заключается в проверке Number
собственность SqlException
,
(Это на самом деле возвращает номер ошибки с первого SqlError
в Errors
коллекции, но в вашем случае транспортная ошибка должна быть единственной в коллекции.)
Я видел, как это происходило в моей среде несколько раз. Клиентское приложение в этом случае установлено на многих машинах. Некоторые из этих машин оказались ноутбуками, люди оставляли приложение открытым, отключая его, а затем снова подключая и пытаясь использовать. Это приведет к указанной вами ошибке.
Первым делом я хотел бы посмотреть на сеть и убедиться, что серверы не работают по протоколу DHCP, а обновление IP-адресов вызывает эту ошибку. Если это не так, то вы должны начать просматривать журналы событий в поисках другой сети.
К сожалению, это как указано выше, ошибка сети. Главное, что вы можете сделать, это просто контролировать соединения с помощью такого инструмента, как netmon, и работать оттуда.
Удачи.
Использовать Enterprise Services с транзакционными компонентами
Я использую слой надежности вокруг моих команд БД (абстрагируется в хранилище Interfaece). По сути, это просто код, который перехватывает любое ожидаемое исключение (DbException, а также InvalidOperationException, которое возникает при возникновении проблем с подключением), регистрирует его, собирает статистику и повторяет все заново.
При наличии этого уровня надежности сервис смог изящно пережить стресс-тестирование (постоянные тупики, сбои сети и т. Д.). Производство гораздо менее враждебно, чем это.
PS: здесь есть еще кое-что (наряду с простым способом определения надежности с помощью перехвата DSL).
У меня была такая же проблема, хотя она была с запросами на обслуживание к базе данных SQL.
Это то, что у меня было в моем сервисном журнале ошибок:
System.Data.SqlClient.SqlException: произошла ошибка транспортного уровня при отправке запроса на сервер. (провайдер: провайдер TCP, ошибка: 0 - существующее соединение было принудительно закрыто удаленным хостом.)
У меня есть набор тестов C#, который тестирует сервис. Служба и БД находились на внешних серверах, поэтому я подумал, что это может быть проблемой. Поэтому я развернул службу и БД локально безрезультатно. Проблема продолжалась. Набор тестов - это даже не сложный тест производительности, поэтому я понятия не имел, что происходит. Один и тот же тест не удавался каждый раз, но когда я отключал этот тест, другой тест проходил постоянно.
Я попробовал другие методы, предложенные в Интернете, которые тоже не работали:
- Увеличьте значения реестра TcpMaxDataRetransmissions и TcpMaxConnectRetransmissions.
- Отключите параметр "Общая память" в диспетчере конфигурации SQL Server в разделе "Клиентские протоколы" и сортируйте TCP/IP по 1-му в списке.
- Это может произойти при тестировании масштабируемости с большим количеством попыток подключения клиента. Чтобы устранить эту проблему, используйте утилиту regedit.exe, чтобы добавить новое значение DWORD с именем SynAttackProtect в раздел реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\ со значением данных 00000000.
Моим последним средством было использовать старость, говоря: "Попробуй и попробуй еще раз". Поэтому я вложил операторы try-catch, чтобы гарантировать, что в случае потери соединения TCP/IP в низком протоколе связи он не просто сдается, а пытается снова. Теперь это работает для меня, но это не очень элегантное решение.
У меня такая же проблема. Я спросил у моих друзей-гиков сети, и все сказали, что люди ответили здесь: это связь между компьютером и сервером базы данных. В моем случае проблема заключалась в моем интернет-провайдере или маршрутизаторе. После обновления роутера проблема ушла. Но есть ли у вас какие-либо другие пропуски интернет-соединения с вашего компьютера или сервера? Я имел...
Я столкнулся с ошибкой транспорта сегодня утром в SSMS при подключении к SQL 2008 R2 Express.
Я пытался импортировать CSV с \r\n. Я закодировал мой терминатор строки для 0x0d0x0a. Когда я изменил его на 0x0a, ошибка прекратилась. Я могу изменить это назад и вперед и наблюдать, как это происходит / не случается.
BULK INSERT #t1 FROM 'C:\123\Import123.csv' WITH
( FIRSTROW = 1, FIELDTERMINATOR = ',', ROWTERMINATOR = '0x0d0x0a' )
Я подозреваю, что неправильно пишу свой терминатор строки, потому что SQL анализирует один символ за раз, в то время как я пытаюсь передать два символа.
Так или иначе, этой ошибке уже 4 года, но она может предоставить немного информации для следующего пользователя.
Я просто хотел опубликовать здесь исправление, которое помогло нашей компании установить новое программное обеспечение, которое мы установили. Начиная с 1-го дня в файле журнала клиента мы получили следующую ошибку: Серверу не удалось обработать запрос. ---> Произошла ошибка транспортного уровня при получении результатов с сервера. (поставщик: поставщик TCP, ошибка: 0 - истекло время ожидания семафора.) ---> истекло время ожидания семафора.
Проблема была полностью решена путем настройки агрегата ссылок (LAG) на нашем коммутаторе. Наш сервер Dell FX1 имеет резервные оптоволоконные линии, выходящие из задней части. Мы не осознавали, что коммутатор, к которому они подключены, должен иметь настроенную группу LAG на этих двух портах. Подробности смотрите здесь: https://docs.meraki.com/display/MS/Switch+Ports
Вам также следует проверить аппаратное подключение к базе данных.
Возможно, эта ветка будет полезна: http://channel9.msdn.com/forums/TechOff/234271-Conenction-forcibly-closed-SQL-2005/