Indagine dettagliata sull'eccezione del timeout WCF


94

Abbiamo un'applicazione che ha un servizio WCF (* .svc) in esecuzione su IIS7 e vari client che interrogano il servizio. Il server esegue Win 2008 Server. I client eseguono Windows 2008 Server o Windows 2003 Server. Ricevo la seguente eccezione, che ho visto può in effetti essere correlata a un gran numero di potenziali problemi di 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. 

Ho aumentato il timeout a 30 minuti e l'errore si è verificato ancora. Questo mi dice che qualcos'altro è in gioco, perché la quantità di dati non potrebbe richiedere 30 minuti per essere caricata o scaricata.

L'errore va e viene. Al momento è più frequente. Non sembra avere importanza se ho 3 client in esecuzione contemporaneamente o 100, si verifica ancora una volta ogni tanto. La maggior parte delle volte non ci sono timeout ma ne ricevo comunque alcuni ogni ora. L'errore proviene da uno dei metodi richiamati. Uno di questi metodi non ha parametri e restituisce un po 'di dati. Un altro accetta molti dati come parametro ma viene eseguito in modo asincrono. Gli errori provengono sempre dal client e non fanno mai riferimento a alcun codice sul server nell'analisi dello stack. Finisce sempre con:

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

Sul server: ho provato (e attualmente ho) le seguenti impostazioni di associazione:

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

Non sembra avere un impatto.

Ho provato (e attualmente ho) le seguenti impostazioni di limitazione:

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

Non sembra avere un impatto.

Al momento ho le seguenti impostazioni per il servizio WCF.

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

Ho funzionato con ConcurrencyMode.Multipleper un po 'e l'errore si è verificato ancora.

Ho provato a riavviare IIS, riavviare il mio SQL Server sottostante, riavviare la macchina. Tutti questi non sembrano avere un impatto.

Ho provato a disabilitare il firewall di Windows. Non sembra avere un impatto.

Sul client, ho queste impostazioni:

maxReceivedMessageSize="2147483647"

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

Il mio cliente chiude le sue connessioni:

var client = new MyClient();

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

Ho modificato le impostazioni del registro per consentire più connessioni in uscita:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32.

Ora ho provato di recente SvcTraceViewer.exe. Sono riuscito a catturare un'eccezione sul lato client. Vedo che la sua durata è di 1 minuto. Guardando la traccia lato server, posso vedere che il server non è a conoscenza di questa eccezione. La durata massima che posso vedere è di 10 secondi.

Ho esaminato le connessioni al database attive utilizzando exec sp_whosul server. Ne ho solo pochi (2-3). Ho esaminato le connessioni TCP da un client utilizzando TCPview. Di solito è intorno a 2-3 e ne ho visti fino a 5 o 6.

In poche parole, sono perplesso. Ho provato tutto ciò che sono riuscito a trovare e deve mancare qualcosa di molto semplice che un esperto WCF sarebbe in grado di vedere. Ho la sensazione viscerale che qualcosa stia bloccando i miei client a basso livello (TCP), prima che il server riceva effettivamente il messaggio e / o che qualcosa stia accodando i messaggi a livello di server e non lasciandoli mai elaborare.

Se dovrei esaminare dei contatori delle prestazioni, fatemelo sapere. (si prega di indicare quali valori sono negativi, poiché alcuni di questi contatori sono difficili da decifrare). Inoltre, come posso registrare la dimensione del messaggio WCF? Infine, ci sono strumenti che mi permettano di testare quante connessioni posso stabilire tra il mio client e il server (indipendentemente dalla mia applicazione)

Grazie per il tuo tempo!

Ulteriori informazioni aggiunte il 20 giugno:

La mia applicazione WCF fa qualcosa di simile al seguente.

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

Utilizzando WireShark, ho visto che quando si verifica l'errore, ho cinque ritrasmissioni TCP seguite da un ripristino TCP in seguito. La mia ipotesi è che l'RST provenga da WCF che interrompe la connessione. Il rapporto di eccezione che ricevo proviene dal timeout del passaggio 3.

L'ho scoperto guardando il flusso tcp "tcp.stream eq 192". Ho quindi esteso il mio filtro a "tcp.stream eq 192 e http e http.request.method eq POST" e ho visto 6 POST durante questo flusso. Sembrava strano, quindi ho controllato con un altro stream come tcp.stream eq 100. Avevo tre POST, il che sembra un po 'più normale perché sto facendo tre chiamate. Tuttavia, chiudo la connessione dopo ogni chiamata WCF, quindi mi sarei aspettato una chiamata per flusso (ma non so molto di TCP).

Indagando un po 'di più, ho scaricato il carico del pacchetto http su disco per vedere cosa queste sei chiamate dove.

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

La mia ipotesi è che due client simultanei stiano utilizzando la stessa connessione, ecco perché ho visto i duplicati. Tuttavia, ho ancora alcuni altri problemi che non riesco a comprendere:

a) Perché il pacchetto è danneggiato? Un colpo di fortuna di rete casuale - forse? Il carico viene compresso con gzip utilizzando questo codice di esempio: http://msdn.microsoft.com/en-us/library/ms751458.aspx - Il codice potrebbe essere difettoso una volta ogni tanto se usato contemporaneamente? Dovrei provare senza la libreria gzip.

b) Perché dovrei vedere i passaggi 1 e 2 in esecuzione DOPO il timeout dell'operazione danneggiata? Mi sembra che queste operazioni non sarebbero dovute avvenire. Forse non sto guardando il flusso giusto perché la mia comprensione del TCP è errata. Ho altri flussi che si verificano contemporaneamente. Dovrei indagare su altri flussi: una rapida occhiata ai flussi 190-194 mostra che il POST Step3 ha dati di carico utili adeguati (non danneggiati). Spingendomi a guardare di nuovo la libreria gzip.


Jason - hai mai risolto questo problema? Era l'impostazione DefaultConnectionLimit?
SFun 28

2
@JasonKealey - A differenza di molte altre domande, non puoi essere accusato di non aver provato da solo prima di postare la domanda :) Mi piace che la tua domanda sia così dettagliata e includa tutti i dettagli importanti. I sintomi che descrivi somigliano molto ai miei, quindi spero che anche la soluzione sia la stessa :)
Øyvind Bråthen

Risposte:


51

Se stai usando il client .Net, potresti non aver impostato

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

ecco la domanda e la risposta originali WCF Service Throttling

Aggiornamento :

Questa configurazione va nell'applicazione client .Net può essere all'avvio o in qualsiasi momento ma prima di iniziare i test.

Inoltre puoi averlo nel file app.config come segue

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

Sembra promettente. L'ho incluso per testarlo durante il mio prossimo test di scalabilità. Sembra esattamente il tipo di impostazione casuale che lo farebbe andare in crash :) Grazie per il puntatore.
Jason Kealey

1
@ Jason: Se sei un programmatore di server sai quanto è importante mantenere la scalabilità del server nelle tue mani e anche uno che sta attualmente soffrendo del problema di concorrenza anche dopo aver usato sopra. Per favore, se puoi esaminare la seguente domanda stackoverflow.com/questions/2637175/wcf-network-cost in breve, soffro di una latenza di 31 ms tra client e server e devo ridurla.
Mubashar

3
Ci è voluto solo un anno, ma alla fine ho eseguito un altro stress test sull'applicazione con questo flag impostato. Il problema sembra risolto, quindi ti do la risposta migliore. Non sarei sorpreso che questo fosse l'ultimo pezzo del puzzle richiesto, ma che tutti gli altri elementi dovevano essere a posto per garantire che l'errore non si verificasse. Grazie mille!
Jason Kealey

2
@ Aris: nell'applicazione client .net, all'avvio o ovunque si imposti la configurazione globale, se si desidera mantenerla configurabile, è possibile aggiungerla nel file di configurazione come questo <system.net> <connectionManagement> <add maxconnection = "200" address = "*" /> </connectionManagement> </system.net>
Mubashar

3

Se non l'hai già provato, incapsula le tue operazioni WCF lato server in blocchi try / latest e aggiungi la registrazione per assicurarti che stiano effettivamente restituendo.

Se questi mostrano che le operazioni sono in corso, il mio prossimo passo sarebbe andare a un livello inferiore e guardare il livello di trasporto effettivo.

A questo punto, Wireshark o un altro strumento simile per l'acquisizione di pacchetti può essere molto utile. Presumo che sia in esecuzione su HTTP sulla porta standard 80.

Esegui Wireshark sul client. Nelle Opzioni quando avvii l'acquisizione, imposta il filtro di acquisizione su tcp http and host service.example.com : questo ridurrà la quantità di traffico irrilevante.

Se puoi, modifica il tuo client per notificarti l'ora esatta di inizio della chiamata e l'ora in cui si è verificato il timeout. O semplicemente monitoralo da vicino.

Quando si riceve un errore, è possibile esplorare i registri di Wireshark per trovare l'inizio della chiamata. Fare clic con il pulsante destro del mouse sul primo pacchetto su cui il client sta chiamando (dovrebbe essere qualcosa come GET /service.svc o POST /service.svc) e selezionare Segui flusso TCP.

Wireshark decodificherà l'intera conversazione HTTP, quindi puoi assicurarti che WCF stia effettivamente restituendo le risposte.


Ho effettuato l'accesso al server, non ci sono errori da questo punto di vista. Sto eseguendo WireShark in questo momento per vedere cosa riesco a trovare. Dato l'elevato volume di traffico, sarà una seccatura da analizzare, ma segnalerò se riesco a trovare qualcosa.
Jason Kealey

Ho eseguito WireShark nelle ultime sei ore e ho raccolto circa 60k frame. Solo un'eccezione è stata segnalata da questo cliente oggi. Ho visto una connessione TCP contrassegnata come RST (reset), apparentemente dopo aver inviato l'e-mail di errore, che probabilmente è WCF che sta terminando la connessione. Ho salvato il payload (525k) su disco. Ho verificato che c'erano altre 87 invocazioni con payload di dimensioni simili. Ho visto alcune ritrasmissioni TCP, ma ne ho viste anche alcune in altre chiamate (che non hanno avuto esito negativo). Comincio a chiedermi del mio hardware di rete + cavi.
Jason Kealey

Anche su una rete locale, la presenza di un TCP ritrasmette non è necessariamente negativa. Se è possibile collegare fisicamente due dei punti finali a un singolo interruttore, potrebbe valere la pena provare, ma non spererei che lo risolva. Se puoi, crea un'applicazione client di base che trasmetta solo un po 'di traffico avanti e indietro al tuo server e nient'altro. Questo può aiutare a eliminare qualsiasi problema nell'applicazione che potrebbe causare timeout.

Inoltre, hai menzionato la visualizzazione del pacchetto TCP Reset: il server ha fornito qualche tipo di risposta a quel punto (o forse stava aspettando più dati)? C'è stato un apprezzabile ritardo tra l'RST e il pacchetto precedente?

Il server è remoto. Sto progettando di creare un ambiente di test localmente per vedere se questo aiuta. Per quanto riguarda l'RST, è stato inviato 34 secondi dopo l'ultima delle cinque ritrasmissioni TCP. (Intervalli da 1 a 8 secondi tra le ritrasmissioni). Questo ti dà qualche indizio?
Jason Kealey

2

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

Per evitare questo errore di timeout, è necessario configurare la proprietà OperationTimeout per Proxy nel codice client WCF. Questa configurazione è qualcosa di nuovo a differenza di altre configurazioni come Send Timeout, Receive Timeout ecc., Di cui ho discusso all'inizio dell'articolo. Per impostare questa configurazione della proprietà di timeout dell'operazione, dobbiamo eseguire il cast del nostro proxy a IContextChannel nell'applicazione client WCF prima di chiamare i metodi del contratto dell'operazione.


L'ho provato. Indipendentemente dal timeout che ho inserito, scade ancora ma questo non ha senso perché l'operazione non è così lunga e perché tutti gli altri client che eseguono le stesse query funzionano durante questo periodo.
Jason Kealey,

I miei test hanno dimostrato che OperationTimeout sovrascrive semplicemente ReceiveTimeout dalla configurazione. Quindi, non serve a niente.
dudeNumber4

2

Ho un problema molto simile. In passato, questo è stato correlato a problemi di serializzazione. Se il problema persiste, puoi verificare di poter serializzare correttamente gli oggetti che stai restituendo. In particolare, se si utilizzano oggetti Linq-To-Sql che hanno relazioni, si verificano problemi di serializzazione noti se si inserisce un riferimento a ritroso su un oggetto figlio all'oggetto padre e si contrassegna quel riferimento a ritroso come DataMember.

Puoi verificare la serializzazione scrivendo un'app console che serializzi e deserializza i tuoi oggetti utilizzando DataContractSerializer sul lato server e qualsiasi metodo di serializzazione utilizzato dal client. Ad esempio, nella nostra applicazione corrente, abbiamo sia client WPF che Compact Framework. Ho scritto un'app console per verificare di poter serializzare usando un DataContractSerializer e deserializzare usando un XmlDesserializer. Potresti provarci.

Inoltre, se stai restituendo oggetti Linq-To-Sql che hanno raccolte figlio, potresti provare a assicurarti di averli caricati con entusiasmo sul lato server. A volte, a causa del caricamento lento, gli oggetti restituiti non vengono popolati e possono causare il comportamento visualizzato nel punto in cui la richiesta viene inviata più volte al metodo del servizio.

Se hai risolto questo problema, mi piacerebbe sapere come perché anche io ci sono bloccato. Ho verificato che il mio problema non sia la serializzazione, quindi sono in perdita.

AGGIORNAMENTO: Non sono sicuro che ti possa aiutare, ma lo strumento Service Trace Viewer ha appena risolto il mio problema dopo 5 giorni di esperienza molto simile alla tua. Impostando la traccia e quindi esaminando l'XML grezzo, ho trovato le eccezioni che stavano causando i miei problemi di serializzazione. Era correlato agli oggetti Linq-to-SQL che occasionalmente avevano più oggetti figlio di quelli che potevano essere serializzati correttamente. L'aggiunta di quanto segue al file web.config dovrebbe consentire la traccia:

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

Il file risultante può essere aperto con lo strumento Service Trace Viewer o semplicemente in IE per esaminare i risultati.


2

Stai chiudendo la connessione al servizio WCF tra le richieste? Se non lo fai, vedrai questo timeout esatto (eventualmente).


2

Ho appena risolto il problema Ho scoperto che i nodi nel file App.config sono stati configurati in modo errato.

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

Conferma la tua configurazione nel nodo <security>, il valore dell'attributo "mode" è "Nessuno". Se il valore è "Transport", si verifica l'errore.


Questo non influisce sulla sicurezza? Se è così, questa potrebbe non essere una soluzione per la maggior parte delle applicazioni reali
Veverke

0

Hai provato a utilizzare clientVia per vedere il messaggio inviato, utilizzando SOAP toolkit o qualcosa del genere? Questo potrebbe aiutare a vedere se l'errore proviene dal client stesso o da qualche altra parte.


Conoscete strumenti più recenti del toolkit SOAP deprecato che mi renderebbero più semplice registrare queste informazioni nelle chiamate WCF?
Jason Kealey

SOAP Toolkit èdeprecated
Kiquenet

0

Hai controllato le tracce WCF? WCF ha la tendenza a ingoiare eccezioni e restituire solo l'ultima eccezione, che è il timeout che stai ottenendo, poiché il punto finale non ha restituito nulla di significativo.


Ho provato SvcTraceViewer e l'unica eccezione segnalata è stata il timeout (sul client). Nulla è stato segnalato sul server.
Jason Kealey,

Apri tutte le opzioni sulla traccia, potresti non avere tutte le opzioni di traccia aperte. Inoltre, controllare sia la traccia degli eventi che i file di traccia dei messaggi.
Miki Watts,

0

Riceverai questo errore anche se stai restituendo un oggetto al client che contiene una proprietà di tipo enum che non è impostata per impostazione predefinita e che enum non ha un valore che mappa a 0. ie enum MyEnum{ a=1, b=2};


0

Sembra che questo messaggio di eccezione sia abbastanza generico e possa essere ricevuto per una serie di motivi. Ci siamo imbattuti in questo durante la distribuzione del client su macchine Windows 8.1. Il nostro client WCF viene eseguito all'interno di un servizio Windows e esegue il polling continuo del servizio WCF. Il servizio Windows viene eseguito con un utente non amministratore. Il problema è stato risolto impostando clientCredentialType su "Windows" nella configurazione WCF per consentire il pass-through dell'autenticazione, come illustrato di seguito:

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

0

Non sono un esperto di WCF ma mi chiedo se non stai riscontrando una protezione DDOS su IIS. So per esperienza che se ad un certo punto esegui un gruppo di connessioni simultanee da un singolo client a un server, il server smette di rispondere alle chiamate poiché sospetta un attacco DDOS. Inoltre, manterrà le connessioni aperte fino al timeout per rallentare il client nei suoi attacchi.

Tuttavia, la connessione multipla proveniente da macchine / IP diversi non dovrebbe essere un problema.

Ci sono ulteriori informazioni in questo post MSDN:

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

Controlla la capacità MaxConcurrentSession.


Sento che questo è ciò che sta accadendo, da tutto ciò che ho visto, comunque ho (sul server): <serviceThrottling maxConcurrentCalls = "150" maxConcurrentInstances = "150" maxConcurrentSessions = "150" /> <serviceDebug includeExceptionDetailInFaults = "true" /> Ci sarebbe un monitor delle prestazioni o un registro IIS che potrei monitorare per vedere se questo sta accadendo?
Jason Kealey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.