Investigación detallada de excepción de tiempo de espera de WCF

94

Tenemos una aplicación que tiene un servicio WCF (* .svc) que se ejecuta en IIS7 y varios clientes consultan el servicio. El servidor está ejecutando Win 2008 Server. Los clientes ejecutan Windows 2008 Server o Windows 2003 Server. Recibo la siguiente excepción, que he visto que de hecho puede estar relacionada con una gran cantidad de posibles problemas de 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. 

Aumenté el tiempo de espera a 30 minutos y el error aún se produjo. Esto me dice que hay algo más en juego, porque la cantidad de datos nunca podría tardar 30 minutos en cargarse o descargarse.

El error va y viene. Por el momento, es más frecuente. No parece importar si tengo 3 clientes ejecutándose simultáneamente o 100, todavía ocurre de vez en cuando. La mayoría de las veces, no hay tiempos de espera, pero todavía obtengo algunos por hora. El error proviene de cualquiera de los métodos que se invocan. Uno de estos métodos no tiene parámetros y devuelve algunos datos. Otro toma muchos datos como parámetro pero se ejecuta de forma asincrónica. Los errores siempre se originan en el cliente y nunca hacen referencia a ningún código del servidor en el seguimiento de la pila. Siempre termina con:

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

En el servidor: he probado (y actualmente tengo) las siguientes configuraciones de enlace:

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

No parece tener impacto.

Probé (y actualmente tengo) las siguientes configuraciones de aceleración:

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

No parece tener impacto.

Actualmente tengo la siguiente configuración para el servicio WCF.

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

Corrí con ConcurrencyMode.Multiple por un tiempo, y el error aún se produjo.

Intenté reiniciar IIS, reiniciar mi SQL Server subyacente, reiniciar la máquina. Todos estos no parecen tener un impacto.

Intenté deshabilitar el firewall de Windows. No parece tener impacto.

En el cliente, tengo estas configuraciones:

maxReceivedMessageSize="2147483647"

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

Mi cliente cierra sus conexiones:

var client = new MyClient();

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

He cambiado la configuración del registro para permitir más conexiones salientes:

MaxConnectionsPerServer=24, MaxConnectionsPer1_0Server=32.

Recientemente he probado SvcTraceViewer.exe. Me las arreglé para atrapar una excepción en el lado del cliente. Veo que su duración es de 1 minuto. Al observar el seguimiento del lado del servidor, puedo ver que el servidor no está al tanto de esta excepción. La duración máxima que puedo ver es de 10 segundos.

He mirado las conexiones de bases de datos activas usando exec sp_who en el servidor. Solo tengo unos pocos (2-3). He mirado las conexiones TCP de un cliente usando TCPview. Suele rondar las 2-3 y he visto hasta 5 o 6.

En pocas palabras, estoy perplejo. He intentado todo lo que pude encontrar y debe faltar algo muy simple que un experto de WCF podría ver. Tengo la intuición de que algo está bloqueando a mis clientes en el nivel bajo (TCP), antes de que el servidor realmente reciba el mensaje y / o que algo está poniendo en cola los mensajes a nivel del servidor y nunca los deja procesar.

Si tiene algún contador de rendimiento que deba consultar, hágamelo saber. (indique qué valores son malos, ya que algunos de estos contadores son difíciles de descifrar). Además, ¿cómo podría registrar el tamaño del mensaje WCF? Finalmente, ¿hay alguna herramienta que me permita probar cuántas conexiones puedo establecer entre mi cliente y el servidor (independientemente de mi aplicación)?

¡Gracias por tu tiempo!

Información adicional agregada el 20 de junio:

Mi aplicación WCF hace algo similar a lo siguiente.

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

Usando WireShark, vi que cuando ocurre el error, tengo cinco retransmisiones de TCP seguidas de un restablecimiento de TCP más adelante. Supongo que el RST proviene de WCF y está matando la conexión. El informe de excepción que recibo es del tiempo de espera de Step3.

Descubrí esto mirando la secuencia tcp "tcp.stream eq 192". Luego expandí mi filtro a "tcp.stream eq 192 y http y http.request.method eq POST" y vi 6 POST durante esta transmisión. Esto parecía extraño, así que verifiqué con otra secuencia como tcp.stream eq 100. Tenía tres POST, lo que parece un poco más normal porque estoy haciendo tres llamadas. Sin embargo, cierro mi conexión después de cada llamada de WCF, por lo que habría esperado una llamada por flujo (pero no sé mucho sobre TCP).

Investigando un poco más, volqué la carga del paquete http en el disco para ver dónde estaban estas seis llamadas.

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

Supongo que dos clientes simultáneos están usando la misma conexión, por eso vi duplicados. Sin embargo, todavía tengo algunos problemas más que no puedo comprender:

a) ¿Por qué está dañado el paquete? Una casualidad de la red, ¿quizás? La carga está comprimida en gzip usando este código de muestra: http://msdn.microsoft.com/en-us/library/ms751458.aspx - ¿Podría el código tener errores de vez en cuando cuando se usa al mismo tiempo? Debería probar sin la biblioteca gzip.

b) ¿Por qué vería los pasos 1 y 2 ejecutándose DESPUÉS de que se agotó el tiempo de espera de la operación dañada? Me parece que estas operaciones no deberían haber ocurrido. Quizás no estoy viendo la transmisión correcta porque mi comprensión de TCP es defectuosa. Tengo otras corrientes que ocurren al mismo tiempo. Debo investigar otras transmisiones: un vistazo rápido a las transmisiones 190-194 muestra que Step3 POST tiene datos de carga útil adecuados (no corruptos). Empujándome a mirar la biblioteca gzip de nuevo.

Jason Kealey
fuente
Jason, ¿alguna vez resolviste este problema? ¿Fue la configuración DefaultConnectionLimit?
SFun28
2
@JasonKealey: a diferencia de muchas otras preguntas, no se te puede acusar de no intentarlo por ti mismo antes de publicar la pregunta :) Me encanta que tu pregunta sea tan detallada e incluya todos los detalles importantes. Los síntomas que describe se parecen mucho a los míos, así que espero que la solución también sea la misma :)
Øyvind Bråthen

Respuestas:

51

Si está utilizando el cliente .Net, es posible que no haya configurado

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

aquí está la pregunta original y la respuesta WCF Service Throttling

Actualización :

Esta configuración va en la aplicación cliente .Net puede estar en el inicio o cuando sea, pero antes de comenzar sus pruebas.

Además, puede tenerlo en el archivo app.config, así como seguir

<system.net>
    <connectionManagement>
      <add maxconnection = "200" address ="*" />
    </connectionManagement>
  </system.net>
Mubashar
fuente
Esto parece prometedor. Incluí esto para probarlo durante mi próxima prueba de escalabilidad. Se ve exactamente como el tipo de configuración aleatoria que lo haría fallar :) Gracias por el puntero.
Jason Kealey
1
@Jason: si usted es un programador de servidores, sabe lo importante que es mantener la escalabilidad del servidor en sus manos y también uno que actualmente está sufriendo el problema de concurrencia incluso después de usar el anterior. Por favor, si puede consultar la siguiente pregunta stackoverflow.com/questions/2637175/wcf-network-cost, en resumen, estoy sufriendo con una latencia de 31ms entre el cliente y el servidor y necesito reducirla.
Mubashar
3
Solo tomó un año, pero finalmente realicé otra prueba de esfuerzo en la aplicación con este conjunto de banderas. El problema parece estar resuelto, así que te estoy dando la mejor respuesta. No me sorprendería que esta fuera la última pieza del rompecabezas que se requería, pero que todos los demás elementos debían estar en su lugar para garantizar que no ocurriera el error. ¡Muchas gracias!
Jason Kealey
2
@Aris: en la aplicación de cliente .net, al inicio o donde sea que establezca su configuración global, si desea mantenerla configurable, puede agregarla en el archivo de configuración, así como en este <system.net> <connectionManagement> <add maxconnection = "200" address = "*" /> </connectionManagement> </system.net>
Mubashar
3

Si aún no lo ha probado, encapsule sus operaciones WCF del lado del servidor en bloques try / finalmente, y agregue el registro para asegurarse de que realmente estén regresando.

Si muestran que las Operaciones se están completando, entonces mi siguiente paso sería ir a un nivel inferior y mirar la capa de transporte real.

Wireshark u otra herramienta de captura de paquetes similar puede ser muy útil en este momento. Supongo que esto se ejecuta a través de HTTP en el puerto estándar 80.

Ejecute Wireshark en el cliente. En las Opciones, cuando inicie la captura, configure el filtro de captura en tcp http and host service.example.com : esto reducirá la cantidad de tráfico irrelevante.

Si puede, modifique su cliente para que le notifique la hora exacta de inicio de la llamada y la hora en que se agotó el tiempo de espera. O simplemente vigílelo de cerca.

Cuando recibe un error, puede rastrear los registros de Wireshark para encontrar el inicio de la llamada. Haga clic con el botón derecho en el primer paquete que tiene su cliente llamando (debería ser algo como GET /service.svc o POST /service.svc) y seleccione Seguir TCP Stream.

Wireshark decodificará toda la conversación HTTP, por lo que puede asegurarse de que WCF realmente está enviando respuestas.


fuente
He iniciado sesión en el servidor; no hay ningún error en ese extremo. Estoy ejecutando WireShark en este momento para ver qué puedo encontrar. Dado el alto volumen de tráfico, va a ser complicado analizarlo, pero informaré si puedo encontrar algo.
Jason Kealey
Ejecuté WireShark durante las últimas seis horas y recopilé unos 60.000 fotogramas. Este cliente solo informó una excepción hoy. Vi una conexión TCP marcada como RST (restablecer), aparentemente después de enviar el correo electrónico de error, que probablemente sea WCF que está terminando la conexión. Guardé la carga útil (525k) en el disco. Verifiqué que había otras 87 invocaciones con cargas útiles de tamaño similar. Vi algunas retransmisiones de TCP, pero también vi algunas en otras llamadas (que no fallaron). Empezando a preguntarme sobre mi hardware de red + cables.
Jason Kealey
Incluso en una red local, la presencia de una retransmisión de TCP no es necesariamente mala. Si es posible conectar físicamente dos de los puntos finales a un solo interruptor, entonces valdría la pena intentarlo, pero no esperaría que lo solucione. Si puede, cree una aplicación cliente muy básica que simplemente pase algo de tráfico de ida y vuelta a su servidor, y nada más. Esto puede ayudar a eliminar cualquier problema en su aplicación que pueda estar causando tiempos de espera.
Además, menciona haber visto el paquete de reinicio de TCP: ¿el servidor había entregado algún tipo de respuesta en ese momento (o quizás estaba esperando más datos)? ¿Hubo un retraso apreciable entre el RST y el paquete anterior?
El servidor es remoto. Estoy planeando crear un entorno de prueba localmente para ver si eso ayuda. En cuanto al RST, se envió 34 segundos después de la última de las cinco retransmisiones de TCP. (Intervalos de 1 a 8 segundos entre retransmisiones). ¿Eso te da alguna pista?
Jason Kealey
2

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

Para evitar este error de tiempo de espera, debemos configurar la propiedad OperationTimeout para Proxy en el código de cliente WCF. Esta configuración es algo nuevo a diferencia de otras configuraciones como Send Timeout, Receive Timeout, etc., que discutí al principio del artículo. Para establecer esta configuración de propiedad de tiempo de espera de operación, tenemos que convertir nuestro proxy a IContextChannel en la aplicación de cliente WCF antes de llamar a los métodos de contrato de operación.

Joel martinez
fuente
He probado esto. Independientemente del tiempo de espera que puse, todavía se agota, pero esto no tiene sentido porque la operación no es tan larga y porque todos los demás clientes que hacen las mismas consultas funcionan durante este tiempo.
Jason Kealey
Mis pruebas demostraron que OperationTimeout simplemente anula ReceiveTimeout de config. Por lo tanto, no sirve de nada.
dudeNumber4
2

Tengo un problema muy similar. En el pasado, esto se ha relacionado con problemas de serialización. Si aún tiene este problema, ¿puede verificar que puede serializar correctamente los objetos que está devolviendo? Específicamente, si está utilizando objetos Linq-To-Sql que tienen relaciones, existen problemas de serialización conocidos si coloca una referencia hacia atrás en un objeto secundario al objeto principal y marca esa referencia hacia atrás como un DataMember.

Puede verificar la serialización escribiendo una aplicación de consola que serialice y deserialice sus objetos usando DataContractSerializer en el lado del servidor y cualquier método de serialización que use su cliente. Por ejemplo, en nuestra aplicación actual, tenemos clientes de WPF y Compact Framework. Escribí una aplicación de consola para verificar que puedo serializar usando un DataContractSerializer y deserializar usando un XmlDesserializer. Puede intentarlo.

Además, si devuelve objetos Linq-To-Sql que tienen colecciones secundarias, puede intentar asegurarse de haberlos cargado con entusiasmo en el lado del servidor. A veces, debido a la carga diferida, los objetos que se devuelven no se completan y pueden causar el comportamiento que está viendo donde la solicitud se envía al método de servicio varias veces.

Si ha resuelto este problema, me encantaría saber cómo, porque yo también estoy atascado. He verificado que mi problema no es la serialización, por lo que estoy perdido.

ACTUALIZACIÓN: No estoy seguro de si le ayudará en algo, pero la herramienta Service Trace Viewer Tool acaba de resolver mi problema después de 5 días de experiencia muy similar a la suya. Al configurar el rastreo y luego mirar el XML sin procesar, encontré las excepciones que estaban causando mis problemas de serialización. Estaba relacionado con los objetos Linq-to-SQL que ocasionalmente tenían más objetos secundarios de los que podían serializarse correctamente. Agregar lo siguiente a su archivo web.config debería habilitar el seguimiento:

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

El archivo resultante se puede abrir con la herramienta Service Trace Viewer Tool o simplemente en IE para examinar los resultados.

Brett Bim
fuente
2

¿Está cerrando la conexión al servicio WCF entre solicitudes? Si no lo hace, verá este tiempo de espera exacto (eventualmente).

aridlehoover
fuente
2

Acabo de resolver el problema. Descubrí que los nodos en el archivo App.config se han confijado incorrectamente.

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

Confirme su configuración en el nodo <security>, el valor del atributo "modo" es "Ninguno". Si su valor es "Transporte", se produce el error.

alexanderlc
fuente
¿Esto no afecta la seguridad? Si es así, esta puede no ser una solución para la mayoría de las aplicaciones reales
Veverke
0

¿ Intentó usar clientVia para ver el mensaje enviado, usando el kit de herramientas SOAP o algo así? Esto podría ayudar a ver si el error proviene del propio cliente o de algún otro lugar.

Philippe
fuente
¿Conoce alguna herramienta más reciente que el obsoleto kit de herramientas SOAP que me facilitaría registrar esta información en las llamadas WCF?
Jason Kealey
El kit de herramientas SOAP esdeprecated
Kiquenet
0

¿Comprobó los seguimientos de WCF? WCF tiende a tragar excepciones y solo devolver la última excepción, que es el tiempo de espera que está obteniendo, ya que el punto final no devolvió nada significativo.

Miki Watts
fuente
Probé SvcTraceViewer y la única excepción que informó fue el tiempo de espera (en el cliente). No se informó nada en el servidor.
Jason Kealey
Abra todas las opciones de la traza, es posible que no tenga todas las opciones de traza abiertas. Además, verifique los archivos de seguimiento de eventos y de mensajes.
Miki Watts
0

También recibirá este error si está devolviendo un objeto al cliente que contiene una propiedad de tipo enum que no está establecida de forma predeterminada y que enum no tiene un valor que se asigne a 0. es decir, enum MyEnum{ a=1, b=2};

tim
fuente
0

Parece que este mensaje de excepción es bastante genérico y se puede recibir debido a una variedad de razones. Nos encontramos con esto al implementar el cliente en máquinas con Windows 8.1. Nuestro cliente WCF se ejecuta dentro de un servicio de Windows y sondea continuamente el servicio WCF. El servicio de Windows se ejecuta bajo un usuario que no es administrador. El problema se solucionó configurando clientCredentialType en "Windows" en la configuración de WCF para permitir el paso de la autenticación, como se muestra a continuación:

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

No soy un experto en WCF, pero me pregunto si no se está encontrando con una protección DDOS en IIS. Sé por experiencia que si ejecuta un montón de conexiones simultáneas desde un solo cliente a un servidor en algún momento, el servidor deja de responder a las llamadas ya que sospecha de un ataque DDOS. También mantendrá las conexiones abiertas hasta que se agoten para ralentizar al cliente en sus ataques.

Sin embargo, la conexión múltiple proveniente de diferentes máquinas / IP no debería ser un problema.

Hay más información en esta publicación de MSDN:

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

Consulte la propiedad MaxConcurrentSession.

jurgenb
fuente
Siento que esto es lo que está sucediendo, de todo lo que he visto, sin embargo tengo (en el servidor): <serviceThrottling maxConcurrentCalls = "150" maxConcurrentInstances = "150" maxConcurrentSessions = "150" /> <serviceDebug includeExceptionDetailInFaults = "true" /> ¿Habría algún monitor de rendimiento o registro de IIS que pudiera supervisar para ver si esto está sucediendo?
Jason Kealey