Детальне розслідування винятків часу очікування WCF


94

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

Моя програма 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 - На відміну від багатьох інших питань, вас не можуть звинуватити в тому, що ви не намагаєтесь до того, як опублікувати запитання :) Мені подобається, що ваше запитання настільки детальне і включає всі важливі деталі. Симптоми, які ви описуєте, дуже схожі на мої, тому я сподіваюся, що рішення теж таке ж :)
Øyvind Bråthen

Відповіді:


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 Service Throttling

Оновлення :

Ця конфігурація входить у програму .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 / final та додайте журналювання, щоб переконатися, що вони фактично повертаються.

Якщо вони показують, що Операції завершуються, то наступним моїм кроком буде перейти на нижчий рівень і подивитися на фактичний транспортний рівень.

На даний момент Wireshark або інший подібний інструмент захоплення пакетів може бути дуже корисним. Я припускаю, що це працює через HTTP на стандартному порту 80.

Запустіть Wireshark на клієнті. У параметрах, коли ви починаєте зйомку, встановіть для фільтра зйомки значення tcp http and host service.example.com - це зменшить кількість неактуального трафіку.

Якщо можете, змініть свого клієнта, щоб повідомити точний час початку дзвінка та час, коли відбувся тайм-аут. Або просто стежте за цим уважно.

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

Wireshark декодує всю розмову HTTP, тому ви можете переконатися, що WCF насправді надсилає відповіді назад.


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

За останні шість годин я провів WireShark і зібрав близько 60 тис. Кадрів. Сьогодні цей клієнт повідомив лише про один виняток. Я бачив з'єднання TCP, позначене як RST (скидання), мабуть, після надсилання повідомлення про помилку, яке, ймовірно, WCF припиняє з'єднання. Я зберігав корисне навантаження (525 тис.) На диск. Я перевірив, що було 87 інших викликів із подібним розміром корисного навантаження. Я бачив кілька повторних передач TCP, але бачив деякі і в інших дзвінках (які не провалилися). Починаючи задаватися питанням про моє мережеве обладнання + кабелі.
Джейсон Кілі

Навіть у локальній мережі наявність ретрансляцій TCP не обов'язково погана. Якщо можливо фізично підключити дві кінцеві точки до одного перемикача, то це, можливо, варто пострілу, але я б не сподівався, що це виправить. Якщо можете - створіть дуже базовий клієнтський додаток, який просто передає трохи трафіку туди-сюди на ваш сервер, і нічого іншого. Це може допомогти усунути будь-яку проблему у вашій програмі, яка може спричиняти час очікування.

Крім того, ви згадуєте, що бачили пакет TCP Reset - чи сервер надав будь-яку відповідь на той момент (або, можливо, він чекав більше даних)? Чи була помітна затримка між 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>

Отриманий файл можна відкрити за допомогою засобу перегляду служб трасування або просто в 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 isdeprecated
Kiquenet

0

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


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

Відкрийте всі параметри трасування, можливо, не всі параметри трасування відкриті. Також перевірте файли трасування подій та файлів трасування повідомлень.
Miki Watts,

0

Ви також отримаєте цю помилку, якщо передаєте клієнту об'єкт, який містить властивість типу enum, яка не встановлена ​​за замовчуванням, і ця 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" maxConcurrentInsests = "150" maxConcurrentSessions = "150" /> <serviceDebug includeExceptionDetailInFaults = "true" /> Чи був би якийсь монітор продуктивності або журнал IIS, який я міг би відстежувати, щоб перевірити, чи це відбувається?
Джейсон Кілі,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.