Подробное исследование исключения тайм-аута WCF


94

У нас есть приложение, в котором есть служба WCF (* .svc), работающая на IIS7, и различные клиенты, запрашивающие службу. На сервере работает Win 2008 Server. Клиенты работают под управлением Windows 2008 Server или Windows 2003 server. Я получаю следующее исключение, которое, как я видел, на самом деле может быть связано с большим количеством потенциальных проблем WCF.

System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9320000. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'http://www.domain.com/WebServices/myservice.svc/gzip' has exceeded the allotted timeout of 00:01:00. The time allotted to this operation may have been a portion of a longer timeout. 

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

Ошибка приходит и уходит. На данный момент это чаще. Кажется, не имеет значения, работают ли у меня 3 клиента одновременно или 100, это все равно происходит время от времени. В большинстве случаев тайм-аутов нет, но я все равно получаю несколько в час. Ошибка возникает из-за любого из вызываемых методов. Один из этих методов не имеет параметров и возвращает немного данных. Другой принимает в качестве параметра много данных, но выполняется асинхронно. Ошибки всегда исходят от клиента и никогда не ссылаются на какой-либо код на сервере в трассировке стека. Он всегда заканчивается:

 at System.Net.HttpWebRequest.GetResponse()
  at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

На сервере: я пробовал (и в настоящее время имею) следующие настройки привязки:

maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647"

Похоже, это не влияет.

Я пробовал (и в настоящее время имею) следующие настройки регулирования:

<serviceThrottling maxConcurrentCalls="1500"   maxConcurrentInstances="1500"    maxConcurrentSessions="1500"/>

Похоже, это не влияет.

В настоящее время у меня есть следующие настройки для службы WCF.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]

Некоторое время я работал ConcurrencyMode.Multiple, но ошибка все еще возникала.

Я попытался перезапустить IIS, перезапустить базовый SQL Server, перезагрузить компьютер. Все это, похоже, не оказывает никакого влияния.

Я пробовал отключить брандмауэр Windows. Похоже, это не влияет.

На клиенте у меня есть такие настройки:

maxReceivedMessageSize="2147483647"

<system.net>
    <connectionManagement>
    <add address="*" maxconnection="16"/>
</connectionManagement> 
</system.net>

Мой клиент закрывает свои соединения:

var client = new MyClient();

try
{
    return client.GetConfigurationOptions();
}
finally
{
    client.Close();
}

Я изменил настройки реестра, чтобы разрешить больше исходящих подключений:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32.

Я только что недавно попробовал SvcTraceViewer.exe. Мне удалось поймать одно исключение на стороне клиента. Я вижу, что его продолжительность составляет 1 минуту. Глядя на трассировку на стороне сервера, я вижу, что сервер не знает об этом исключении. Максимальная продолжительность, которую я вижу, составляет 10 секунд.

Я просмотрел активные соединения с базой данных, используемые exec sp_whoна сервере. У меня их всего несколько (2-3). Я просмотрел TCP-соединения от одного клиента с помощью TCPview. Обычно это около 2-3, а я видел до 5-6.

Проще говоря, я в тупике. Я перепробовал все, что мог найти, и, должно быть, не хватает чего-то очень простого, что мог бы увидеть эксперт по WCF. Мне кажется, что что-то блокирует моих клиентов на низком уровне (TCP) до того, как сервер фактически получит сообщение и / или что что-то ставит сообщения в очередь на уровне сервера и никогда не позволяет им обрабатывать.

Если у вас есть счетчики производительности, на которые мне стоит обратить внимание, дайте мне знать. (укажите, какие значения плохие, так как некоторые из этих счетчиков трудно расшифровать). Кроме того, как я могу зарегистрировать размер сообщения WCF? Наконец, есть ли там какие-либо инструменты, которые позволили бы мне проверить, сколько соединений я могу установить между моим клиентом и сервером (независимо от моего приложения)

Спасибо за ваше время!

Дополнительная информация добавлена ​​20 июня:

Мое приложение WCF делает примерно следующее.

while (true)
{
   Step1GetConfigurationSettingsFromServerViaWCF(); // can change between calls
   Step2GetWorkUnitFromServerViaWCF();
   DoWorkLocally(); // takes 5-15minutes. 
   Step3SendBackResultsToServerViaWCF();
}

Используя WireShark, я действительно увидел, что при возникновении ошибки у меня есть пять повторных передач TCP с последующим сбросом TCP позже. Я предполагаю, что RST исходит из WCF, убивающего соединение. Отчет об исключении, который я получаю, исходит из тайм-аута Step3.

Я обнаружил это, посмотрев на tcp-поток "tcp.stream eq 192". Затем я расширил свой фильтр до «tcp.stream eq 192 и http и http.request.method eq POST» и увидел 6 POST во время этого потока. Это казалось странным, поэтому я проверил с другим потоком, например tcp.stream eq 100. У меня было три POST, что кажется немного более нормальным, потому что я делаю три вызова. Однако я закрываю свое соединение после каждого вызова WCF, поэтому я ожидал одного вызова для каждого потока (но я мало знаю о TCP).

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

1) Step3
2) Step1
3) Step2
4) Step3 - corrupted
5) Step1
6) Step2

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

а) Почему пакет поврежден? Случайная сетевая случайность - может быть? Загрузка сжимается с помощью этого образца кода: http://msdn.microsoft.com/en-us/library/ms751458.aspx - Может ли код иногда приводить к ошибкам при одновременном использовании? Я должен протестировать без библиотеки gzip.

б) Почему я вижу, что шаги 1 и 2 выполняются ПОСЛЕ истечения времени ожидания поврежденной операции? Мне кажется, что этих операций не должно было произойти. Возможно, я не смотрю нужный поток, потому что мое понимание TCP ошибочно. У меня есть другие потоки, которые происходят в то же время. Я должен исследовать другие потоки - быстрый взгляд на потоки 190-194 показывает, что Step3 POST имеет правильные данные полезной нагрузки (не повреждены). Заставляет меня снова взглянуть на библиотеку gzip.


Джейсон - ты когда-нибудь решал эту проблему? Это был параметр DefaultConnectionLimit?
SFun28

2
@JasonKealey - В отличие от многих других вопросов, вас нельзя обвинить в том, что вы не пытались сами перед тем, как опубликовать вопрос :) Мне нравится, что ваш вопрос настолько подробный и включает все важные детали. Симптомы, которые вы описываете, очень похожи на мои, так что я надеюсь, что решение тоже будет таким же :)
Эйвинд Братен

Ответы:


51

Если вы используете клиент .Net, возможно, вы не установили

//This says how many outgoing connection you can make to a single endpoint. Default Value is 2
System.Net.ServicePointManager.DefaultConnectionLimit = 200;

вот исходный вопрос и ответ Регулирование службы WCF

Обновление :

Эта конфигурация входит в .Net клиентское приложение может быть запущено или когда угодно, но до запуска ваших тестов.

Кроме того, вы можете иметь его в файле app.config, а также в следующем

<system.net>
    <connectionManagement>
      <add maxconnection = "200" address ="*" />
    </connectionManagement>
  </system.net>

Это выглядит многообещающе. Я включил это для тестирования во время следующего теста на масштабируемость. Это похоже на случайную настройку, которая может привести к сбою :) Спасибо за указатель.
Джейсон Кили

1
@Jason: Если вы серверный программист, вы знаете, насколько важно поддерживать масштабируемость сервера в ваших руках, а также тот, кто в настоящее время страдает от проблемы параллелизма даже после использования выше. Пожалуйста, если вы можете изучить следующий вопрос stackoverflow.com/questions/2637175/wcf-network-cost вкратце, я страдаю от задержки 31 мс между клиентом и сервером, и мне нужно ее уменьшить.
Мубашар

3
Это заняло всего год, но я, наконец, провел еще один стресс-тест приложения с этим флагом. Проблема кажется решенной, поэтому я дам вам лучший ответ. Я не удивлюсь, что это был последний кусок головоломки, который требовался, но что все остальные элементы должны были быть на месте, чтобы гарантировать, что ошибка не произойдет. Огромное спасибо!
Джейсон Кили

2
@Aris: В клиентском приложении .net, при запуске или где бы вы ни задавали свою глобальную конфигурацию, если вы хотите сохранить ее настраиваемой, вы можете добавить ее в файл конфигурации, а также это <system.net> <connectionManagement> <add maxconnection = "200" address = "*" /> </connectionManagement> </system.net>
Мубашар

3

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

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

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

Запустите Wireshark на клиенте. В Опциях при запуске захвата установите фильтр захвата на tcp http and host service.example.com - это уменьшит количество нерелевантного трафика.

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

Когда вы получаете сообщение об ошибке, вы можете просмотреть журналы Wireshark, чтобы найти начало вызова. Щелкните правой кнопкой мыши первый пакет, к которому обращается ваш клиент (должно быть что-то вроде GET /service.svc или POST /service.svc), и выберите «Follow TCP Stream».

Wireshark будет декодировать весь HTTP-разговор, поэтому вы можете убедиться, что WCF действительно отправляет ответы.


У меня есть логин на сервере - ошибки нет. Я запускаю WireShark прямо сейчас, чтобы посмотреть, что я могу найти. Учитывая большой объем трафика, его будет сложно анализировать, но я сообщу, если смогу что-нибудь найти.
Джейсон Кили

Я запускал WireShark за последние шесть часов и собрал около 60 тысяч кадров. Сегодня этот клиент сообщил только об одном исключении. Я видел TCP-соединение, помеченное как RST (сброс), по-видимому, после отправки сообщения об ошибке, которое, вероятно, является WCF, который разрывает соединение. Я сохранил полезную нагрузку (525 КБ) на диск. Я подтвердил, что было 87 других вызовов с полезной нагрузкой аналогичного размера. Я видел несколько повторных передач TCP, но видел некоторые и в других вызовах (которые не завершились ошибкой). Начинаю задумываться о моем сетевом оборудовании и кабелях.
Джейсон Кили

Даже в локальной сети наличие TCP Retransmit не обязательно плохо. Если возможно физически подключить две конечные точки к одному коммутатору, то, возможно, стоит попробовать, но я бы не стал надеяться, что это исправит. Если можете - создайте очень простое клиентское приложение, которое просто передает некоторый трафик туда и обратно на ваш сервер и ничего больше. Это может помочь устранить любую проблему в вашем приложении, которая может вызывать тайм-ауты.

Кроме того, вы упомянули, что видели пакет сброса TCP - доставил ли сервер какой-либо ответ в этот момент (или, возможно, он ожидал дополнительных данных)? Была ли заметная задержка между RST и предыдущим пакетом?

Сервер удаленный. Я планирую создать тестовую среду локально, чтобы посмотреть, поможет ли это. Что касается RST, он был отправлен через 34 секунды после последней из пяти повторных передач TCP. (Интервалы между повторными передачами от 1 до 8 секунд). Это дает вам какие-нибудь подсказки?
Джейсон Кили

2

из: http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

Чтобы избежать этой ошибки тайм-аута, нам необходимо настроить свойство OperationTimeout для прокси в коде клиента WCF. Эта конфигурация является чем-то новым, в отличие от других конфигураций, таких как Тайм-аут отправки, Тайм-аут приема и т. Д., Которые я обсуждал в начале статьи. Чтобы установить эту конфигурацию свойства тайм-аута операции, мы должны привести наш прокси к IContextChannel в клиентском приложении WCF перед вызовом методов контракта операции.


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

Мои тесты показали, что OperationTimeout просто переопределяет ReceiveTimeout из конфигурации. Таким образом, это бесполезно.
dudeNumber4

2

У меня очень похожая проблема. В прошлом это было связано с проблемами сериализации. Если проблема не устранена, можете ли вы проверить правильность сериализации возвращаемых вами объектов. В частности, если вы используете объекты Linq-To-Sql, которые имеют отношения, существуют известные проблемы сериализации, если вы поместите обратную ссылку на дочерний объект на родительский объект и отметите эту обратную ссылку как DataMember.

Вы можете проверить сериализацию, написав консольное приложение, которое сериализует и десериализует ваши объекты с помощью DataContractSerializer на стороне сервера и любых методов сериализации, используемых вашим клиентом. Например, в нашем текущем приложении у нас есть клиенты как WPF, так и Compact Framework. Я написал консольное приложение, чтобы убедиться, что я могу сериализовать с помощью DataContractSerializer и десериализовать с помощью XmlDesserializer. Вы можете попробовать это.

Кроме того, если вы возвращаете объекты Linq-To-Sql, у которых есть дочерние коллекции, вы можете попытаться убедиться, что вы с готовностью загрузили их на стороне сервера. Иногда из-за отложенной загрузки возвращаемые объекты не заполняются и могут вызывать наблюдаемое поведение, когда запрос отправляется методу службы несколько раз.

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

ОБНОВЛЕНИЕ: я не уверен, что это поможет вам, но инструмент Service Trace Viewer Tool только что решил мою проблему после 5 дней опыта, очень похожего на ваш. Настроив трассировку, а затем просмотрев необработанный XML, я обнаружил исключения, которые вызывали у меня проблемы с сериализацией. Это было связано с объектами Linq-to-SQL, у которых иногда было больше дочерних объектов, чем можно было успешно сериализовать. Добавление следующего в ваш файл web.config должно включить трассировку:

<sharedListeners>
    <add name="sharedListener"
         type="System.Diagnostics.XmlWriterTraceListener"
         initializeData="c:\Temp\servicetrace.svclog" />
  </sharedListeners>
  <sources>
    <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" >
      <listeners>
        <add name="sharedListener" />
      </listeners>
    </source>
    <source name="System.ServiceModel.MessageLogging" switchValue="Verbose">
      <listeners>
        <add name="sharedListener" />
      </listeners>
    </source>
  </sources>

Полученный файл можно открыть с помощью инструмента Service Trace Viewer Tool или просто в IE для проверки результатов.


2

Вы закрываете соединение со службой WCF между запросами? Если вы этого не сделаете, вы увидите это точное время ожидания (в конце концов).


2

Я только что решил проблему. Я обнаружил, что узлы в файле App.config настроены неправильно.

<client>
<endpoint name="WCF_QtrwiseSalesService" binding="wsHttpBinding" bindingConfiguration="ws" address="http://cntgbs1131:9005/MyService/TGE.ISupplierClientManager" contract="*">
</endpoint>
</client>

<bindings>
    <wsHttpBinding>
        <binding name="ws" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
            <**security mode="None">**
                <transport clientCredentialType="None"></transport>
            </security>
        </binding>
    </wsHttpBinding>
</bindings>

Подтвердите свою конфигурацию в узле <security>, значение атрибута «mode» равно «None». Если ваше значение - «Транспорт», возникает ошибка.


Это не влияет на безопасность? Если так, то это может не подходить для большинства реальных приложений
Веверке

0

Вы пытались использовать clientVia, чтобы увидеть отправленное сообщение, используя набор инструментов SOAP или что-то в этом роде? Это может помочь увидеть, исходит ли ошибка от самого клиента или откуда-то еще.


Знаете ли вы какие-либо инструменты, более свежие, чем устаревший набор инструментов SOAP, которые упростили бы мне регистрацию этой информации в вызовах WCF?
Джейсон Кили,

SOAP Toolkit являетсяdeprecated
Kiquenet

0

Вы проверяли следы WCF? WCF имеет тенденцию поглощать исключения и возвращать только последнее исключение, то есть время ожидания, которое вы получаете, поскольку конечная точка не вернула ничего значимого.


Я попробовал SvcTraceViewer, и единственным исключением, о котором он сообщил, был тайм-аут (на клиенте). На сервере ничего не сообщалось.
Джейсон Кили

Откройте все параметры трассировки, возможно, у вас открыты не все параметры трассировки. Также проверьте файлы трассировки событий и сообщений.
Мики Уоттс

0

Вы также получите эту ошибку, если вы передаете объект обратно клиенту, который содержит свойство типа enum, которое не установлено по умолчанию, и это перечисление не имеет значения, которое сопоставляется с 0. т.е. enum MyEnum{ a=1, b=2};


0

Похоже, это сообщение об исключении является довольно общим и может быть получено по разным причинам. Мы столкнулись с этим при развертывании клиента на машинах с Windows 8.1. Наш клиент WCF работает внутри службы Windows и постоянно опрашивает службу WCF. Служба Windows работает под пользователем без прав администратора. Проблема была устранена путем установки clientCredentialType на «Windows» в конфигурации WCF, чтобы разрешить сквозную аутентификацию, как показано ниже:

      <security mode="None">
        <transport clientCredentialType="Windows" proxyCredentialType="None"
          realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>

0

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

Однако множественное соединение с разных машин / IP-адресов не должно быть проблемой.

В этом сообщении MSDN есть дополнительная информация:

http://msdn.microsoft.com/en-us/library/bb463275.aspx

Проверьте свойство MaxConcurrentSession.


Я чувствую, что это происходит, исходя из всего, что я видел, однако у меня есть (на сервере): <serviceThrottling maxConcurrentCalls = "150" maxConcurrentInstances = "150" maxConcurrentSessions = "150" /> <serviceDebug includeExceptionDetailInFaults = "true" /> Будет ли какой-нибудь монитор производительности или журнал IIS, который я мог бы отслеживать, чтобы узнать, происходит ли это?
Джейсон Кили
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.