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

StackOverflow https://stackoverflow.com/questions/981475

  •  13-09-2019
  •  | 
  •  

Вопрос

У нас есть приложение, в котором есть служба 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-сервер, перезапустить компьютер.Все это, похоже, не оказывает никакого влияния.

Я пробовал отключить брандмауэр 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.Я предполагаю, что ПЕРВЫЙ исходит от WCF, прерывающего соединение.Отчет об исключении, который я получаю, относится к тайм-ауту шага 3.

Я обнаружил это, просмотрев поток tcp "tcp.stream eq 192".Затем я расширил свой фильтр до "tcp.stream eq 192 и http и http.request.method eq POST" и увидел 6 сообщений во время этого потока.Это показалось странным, поэтому я проверил с помощью другого потока, такого как tcp.stream eq 100.У меня было три сообщения, что кажется немного более нормальным, потому что я делаю три звонка.Однако я закрываю свое соединение после каждого вызова 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 содержит правильные данные полезной нагрузки (не повреждено).Подталкивает меня снова взглянуть на библиотеку gzip.

Это было полезно?

Решение

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

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

вот оригинальный вопрос и ответ Регулирование сервиса WCF

Обновить:

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

Более того, вы также можете разместить это в файле app.config, как показано ниже

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

Другие советы

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

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

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

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

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

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

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

От: http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

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

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

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

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

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

Обновить:Я не уверен, поможет ли это вам как-нибудь, но инструмент просмотра трассировки служб только что решил мою проблему после 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 для просмотра результатов.

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

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

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

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

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

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

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

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

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

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

Ознакомьтесь со свойством MaxConcurrentSession sproperty.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top