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

У нас есть приложение, которое имеет службу WCF (*.svc), работающую на IIS7, и различные клиенты, запрашивающие эту службу. На сервере работает Win 2008 Server. Клиенты работают либо на сервере Windows 2008 Server, либо на Windows 2003. Я получаю следующее исключение, которое, как я видел, фактически может быть связано с большим количеством потенциальных проблем 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 июня:

My WCF-приложение делает что-то похожее на следующее.

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

Используя WireShark, я видел, что когда возникает ошибка, у меня есть пять повторных передач TCP, за которыми позже следует TCP reset. Я предполагаю, что 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

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

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

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

Ответ 1

Если вы используете .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>

Ответ 2

Если вы уже не попробовали - инкапсулируйте свои операции 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 фактически отправляет ответы.

Ответ 3

from: http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

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

Ответ 4

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

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

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

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

UPDATE: я не уверен, что это поможет вам, но инструмент Service Trace Viewer просто решил мою проблему после 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>

Полученный файл можно открыть с помощью средства просмотра трассировки служб или только в IE, чтобы проверить результаты.

Ответ 5

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

Ответ 6

Я только что решил проблему. Я обнаружил, что узлы в файле 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>

Подтвердите свою конфигурацию в node <security>, значение атрибута "режим" - "Нет". Если ваше значение - "Транспорт", возникает ошибка.

Ответ 8

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

Ответ 9

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

Несколько соединений, идущих с разных компьютеров /IP, не должны быть проблемой.

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

Похоже, это сообщение об исключительной ситуации является довольно общим и может быть получено по разным причинам. Мы столкнулись с этим при развертывании клиента на машинах 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>