web-dev-qa-db-fra.com

Enquête détaillée sur l'exception d'expiration du délai d'attente WCF

Nous avons une application qui a un service WCF (* .svc) s'exécutant sur IIS7 et divers clients interrogeant le service. Le serveur exécute Win 2008 Server. Les clients exécutent Windows 2008 Server ou Windows 2003 Server. Je reçois l’exception suivante, qui, j’ai vu, peut en fait être liée à un grand nombre de problèmes potentiels de la 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. 

J'ai augmenté le délai d'attente à 30min et l'erreur s'est toujours produite. Cela me dit que quelque chose d'autre est en jeu, car la quantité de données ne pourrait jamais prendre 30 minutes à télécharger ou à télécharger. 

L'erreur va et vient. Pour le moment, c'est plus fréquent. Cela ne semble pas avoir d'importance si j'ai 3 clients fonctionnant simultanément ou 100, cela se produit encore de temps en temps. La plupart du temps, il n'y a pas de délai d'attente, mais j'en ai encore quelques par heure. L'erreur provient d'une des méthodes invoquées. L'une de ces méthodes n'a pas de paramètres et renvoie un bit de données. Un autre prend beaucoup de données en paramètre mais s'exécute de manière asynchrone. Les erreurs proviennent toujours du client et ne font jamais référence à aucun code sur le serveur dans la trace de la pile. Il se termine toujours par: 

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

Sur le serveur: J'ai essayé (et ai actuellement) les paramètres de liaison suivants:

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

Cela ne semble pas avoir d'impact. 

J'ai essayé (et ai actuellement) les paramètres de limitation suivants:

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

Cela ne semble pas avoir d'impact. 

J'ai actuellement les paramètres suivants pour le service WCF. 

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

J'ai couru avec ConcurrencyMode.Multiple pendant un moment, et l'erreur s'est toujours produite. 

J'ai essayé de redémarrer IIS, de redémarrer mon serveur SQL Server sous-jacent, de redémarrer la machine. Tout cela ne semble pas avoir d'impact. 

J'ai essayé de désactiver le pare-feu Windows. Cela ne semble pas avoir d'impact. 

Sur le client, j'ai ces paramètres: 

maxReceivedMessageSize="2147483647"

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

Mon client ferme ses connexions:

var client = new MyClient();

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

J'ai modifié les paramètres du registre pour autoriser davantage de connexions sortantes:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32.

Je viens tout juste d'essayer SvcTraceViewer.exe. J'ai réussi à attraper une exception du côté client. Je vois que sa durée est de 1 minute. En regardant la trace côté serveur, je peux voir que le serveur n'est pas conscient de cette exception. La durée maximale que je peux voir est de 10 secondes. 

J'ai examiné les connexions de base de données actives à l'aide de exec sp_who sur le serveur. Je n'en ai que quelques uns (2-3). J'ai examiné les connexions TCP d'un client utilisant TCPview. Il est généralement autour de 2-3 et j'ai vu jusqu'à 5 ou 6. 

En termes simples, je suis perplexe. J'ai essayé tout ce que je pouvais trouver et il me manque quelque chose de très simple qu'un expert de la WCF serait capable de voir. J’ai l’impression que quelque chose bloque mes clients au niveau bas (TCP), avant que le serveur reçoive réellement le message et/ou que quelque chose mette les messages en file d’attente au niveau du serveur sans les laisser traiter. 

Si vous avez des compteurs de performance que je devrais examiner, veuillez me le faire savoir. (veuillez indiquer quelles valeurs sont mauvaises, car certains de ces compteurs sont difficiles à déchiffrer). Aussi, comment pourrais-je enregistrer la taille du message WCF? Enfin, existe-t-il des outils qui me permettraient de tester le nombre de connexions que je peux établir entre mon client et mon serveur (indépendamment de mon application)?

Merci pour votre temps!

Informations supplémentaires ajoutées le 20 juin:

Mon application WCF fait quelque chose de similaire à ce qui suit.

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

En utilisant WireShark, j’ai vu que lorsque l’erreur se produisait, j’ai cinq retransmissions TCP suivies d’une réinitialisation TCP ultérieurement. Je suppose que la taxe de vente au détail provient de la WCF et tue la connexion. Le rapport d'exception que je reçois provient de l'expiration de l'étape 3. 

J'ai découvert cela en regardant le flux tcp "tcp.stream eq 192". J'ai ensuite étendu mon filtre à "tcp.stream eq 192 et http et http.request.method eq POST" et j'ai vu 6 POST au cours de ce flux. Cela semblait étrange, alors j'ai vérifié avec un autre flux tel que tcp.stream eq 100. J'avais trois POST, ce qui semble un peu plus normal parce que je fais trois appels. Cependant, je ferme ma connexion après chaque appel WCF, donc je m'attendais à un appel par flux (mais je ne connais pas grand chose au sujet de TCP). 

En cherchant un peu plus, j'ai vidé le chargement de paquets http sur le disque pour voir où étaient ces six appels.1) Step3 2) Step1 3) Step2 4) Step3 - corrupted 5) Step1 6) Step2

A) Pourquoi le paquet est-il corrompu? Coup de hasard sur le réseau - peut-être? La charge est gzippée à l'aide de cet exemple de code: http://msdn.Microsoft.com/en-us/library/ms751458.aspx - Le code peut-il être bogué de temps en temps lorsqu'il est utilisé simultanément? Je devrais tester sans la bibliothèque gzip.

b) Pourquoi les étapes 1 et 2 seraient-elles exécutées APRÈS l'expiration de l'opération corrompue? Il me semble que ces opérations n'auraient pas dû se produire. Peut-être que je ne regarde pas le bon flux parce que ma compréhension de TCP est erronée. J'ai d'autres flux qui se produisent en même temps. Je devrais étudier d'autres flux - un rapide coup d'œil sur les flux 190-194 montre que le Step3 POST possède les données utiles appropriées (non corrompues). Me poussant à regarder à nouveau la bibliothèque gzip. 

b) Why would I see step 1 & step 2 running AFTER the corrupted operation timed out? It seems to me as if these operations should not have occurred. Maybe I am not looking at the right stream because my understanding of TCP is flawed. I have other streams that occur at the same time. I should investigate other streams - a quick glance at streams 190-194 show that the Step3 POST have proper payload data (not corrupted). Pushing me to look at the gzip library again.

93
Jason Kealey

Si vous utilisez un client .Net, vous n’avez peut-être pas défini 

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

voici la question et la réponse d'origine WCF Service Throttling

Mettre à jour

Cette configuration va dans l'application client .Net peut être au démarrage ou à tout moment, mais avant de commencer vos tests. 

De plus, vous pouvez l'avoir dans le fichier app.config comme suit: 

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

Si vous ne l'avez pas déjà essayé, encapsulez vos opérations WCF côté serveur dans des blocs try/finally et ajoutez une journalisation pour vous assurer qu'elles retournent réellement. 

Si ceux-ci indiquent que les opérations sont terminées, l'étape suivante consiste à passer à un niveau inférieur et à examiner la couche de transport proprement dite. 

Wireshark ou un autre outil de capture de paquets similaire peut être très utile à ce stade. Je suppose que cela fonctionne sur HTTP sur le port standard 80. 

Exécutez Wireshark sur le client. Dans les Options lorsque vous démarrez la capture, définissez le filtre de capture sur tcp http and Host service.example.com - cela réduira la quantité de trafic non pertinent. 

Si vous le pouvez, modifiez votre client pour vous informer de l'heure exacte de début de l'appel et de l'heure à laquelle le délai a expiré. Ou juste le surveiller de près. 

Lorsque vous obtenez une erreur, vous pouvez parcourir les journaux Wireshark pour rechercher le début de l'appel. Cliquez avec le bouton droit sur le premier paquet sur lequel votre client appelle (ce doit être quelque chose comme GET /service.svc ou POST /service.svc) et sélectionnez Suivre le flux TCP. 

Wireshark décodera l'intégralité de la conversation HTTP afin que vous puissiez vous assurer que WCF envoie effectivement les réponses. 

3
user111013

à partir de: http://www.codeproject.com/KB/WCF/WCF_Operation_Timeout_.aspx

Pour éviter cette erreur de délai d'attente, nous avons besoin de pour configurer OperationTimeout propriété pour proxy dans le client WCF code. Cette configuration est quelque chose nouveau contrairement à d'autres configurations telles comme délai d’envoi, délai de réception, etc., dont j'ai discuté tôt dans le article. Pour définir le délai d’exécution de cette opération configuration de la propriété, nous devons Transmettre notre proxy à IContextChannel en Application cliente WCF avant d'appeler les méthodes du contrat d'exploitation.

2
Joel Martinez

Fermez-vous la connexion au service WCF entre les demandes? Si vous ne le faites pas, vous verrez cette temporisation exacte (éventuellement).

2
aridlehoover

J'ai un problème très similaire. Dans le passé, cela était lié à des problèmes de sérialisation. Si vous rencontrez toujours ce problème, pouvez-vous vérifier que vous pouvez sérialiser correctement les objets que vous renvoyez. En particulier, si vous utilisez des objets Linq-To-Sql ayant des relations, des problèmes de sérialisation sont connus si vous placez une référence arrière sur un objet enfant sur l'objet parent et que vous la marquez en tant que DataMember.

Vous pouvez vérifier la sérialisation en écrivant une application de console qui sérialise et désérialise vos objets à l'aide de DataContractSerializer côté serveur et des méthodes de sérialisation utilisées par votre client. Par exemple, dans notre application actuelle, nous avons à la fois des clients WPF et Compact Framework. J'ai écrit une application console pour vérifier que je peux sérialiser à l'aide d'un DataContractSerializer et désérialiser à l'aide d'un XmlDesserializer. Vous pourriez essayer ça.

De même, si vous renvoyez des objets Linq-To-Sql avec des collections enfants, vous pouvez vous assurer que vous les avez chargés avec impatience côté serveur. Parfois, à cause d'un chargement paresseux, les objets renvoyés ne sont pas renseignés et peuvent provoquer le problème que vous constatez lorsque la demande est envoyée à la méthode de service à plusieurs reprises.

Si vous avez résolu ce problème, j'aimerais savoir comment, parce que je suis aussi pris au piège. J'ai vérifié que mon problème n'était pas de la sérialisation, alors je suis perdu.

MISE À JOUR: Je ne suis pas sûr que cela vous aidera, mais l'outil Service Trace Viewer a résolu mon problème après 5 jours d'expérience très similaire à la vôtre. En configurant le traçage puis en examinant le XML brut, j'ai trouvé les exceptions à l'origine de mes problèmes de sérialisation. Il était lié à des objets Linq-to-SQL qui avaient parfois plus d'objets enfants que ce qui pouvait être sérialisé avec succès. L'ajout des éléments suivants à votre fichier web.config devrait permettre le traçage:

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

Le fichier résultant peut être ouvert à l'aide de l'outil Service Trace Viewer ou uniquement dans IE pour examiner les résultats.

2
Brett Bim

Je viens de résoudre le problème. J'ai constaté que les nœuds du fichier App.config avaient été mal configurés.

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

Confirmez votre configuration dans le noeud <security>, la valeur de l'attribut "mode" est "Aucune". Si votre valeur est "Transport", l'erreur se produit.

2
alexanderlc
1
Rakoun

Avez-vous vérifié les traces de la WCF? WCF a tendance à avaler des exceptions et à ne renvoyer que la dernière exception, le délai d'attente que vous obtenez, car le point final n'a renvoyé rien de significatif.

0
Miki Watts

Je ne suis pas un expert de la WCF, mais je me demande si vous ne rencontrez pas de protection DDOS sur IIS . Je sais par expérience que si vous exécutez plusieurs connexions simultanées d'un client à un serveur, pointer le serveur cesse de répondre aux appels car il suspecte une attaque DDOS . Il maintiendra également les connexions ouvertes jusqu'à leur expiration afin de ralentir le client dans ses attaques.

Les connexions multiples provenant de différentes machines/IP ne devraient toutefois pas poser de problème.

Il y a plus d'informations dans ce message MSDN:

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

Découvrez la sproperty MaxConcurrentSession.

0
jurgenb

Vous recevrez également cette erreur si vous transmettez au client un objet contenant une propriété de type enum qui n'est pas définie par défaut et qui n'a pas de valeur correspondant à 0. i.e enum MyEnum{ a=1, b=2};

0
tim

On dirait que ce message d'exception est assez générique et peut être reçu pour diverses raisons. Nous avons rencontré ce problème lors du déploiement du client sur des ordinateurs Windows 8.1. Notre client WCF s'exécute dans un service Windows et interroge en permanence le service WCF. Le service Windows s'exécute sous un utilisateur non-administrateur. Le problème a été résolu en définissant clientCredentialType sur "Windows" dans la configuration WCF pour permettre l'authentification, notamment dans l'exemple suivant:

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

Avez-vous essayé d’utiliser clientVia pour voir le message envoyé à l’aide de SOAP toolkit ou quelque chose du genre? Cela pourrait aider à voir si l'erreur provient du client lui-même ou d'un autre endroit.

0
Philippe