Problemas de rendimiento al realizar llamadas a servicios web desde una ASP.NET aplicación
En este artículo se proporciona ayuda para resolver los problemas de rendimiento que se producen al realizar llamadas a servicios web desde una Microsoft ASP.NET aplicación.
Versión del producto original: ASP.NET
Número KB original: 821268
Síntomas
Al realizar llamadas a servicios web desde una aplicación ASP.NET, puede experimentar contención, bajo rendimiento y interbloqueos. Los clientes pueden informar de que las solicitudes dejan de responder o tardar mucho tiempo en ejecutarse. Si se sospecha que hay un interbloqueo, el proceso de trabajo puede reciclarse.
Puede recibir el siguiente mensaje de error de excepción al realizar una llamada al HttpWebRequest.GetResponse método:
"System.InvalidOperationException: no había suficientes subprocesos libres en el objeto ThreadPool para completar la operación".
También puede recibir el siguiente mensaje de error de excepción en el explorador:
"HttpException (0x80004005): Solicitud con tiempo de espera."
Nota
Este artículo también se aplica a las aplicaciones que hacen HttpWebRequest solicitudes directamente.
Causa
Este problema puede producirse porque ASP.NET número de subprocesos de trabajo y subprocesos de puerto de finalización que una llamada puede usar para ejecutar solicitudes.
Normalmente, una llamada a un servicio web usa un subproceso de trabajo para ejecutar el código que envía la solicitud y un subproceso de puerto de finalización para recibir la devolución de llamada del servicio web. Sin embargo, si la solicitud se redirige o requiere autenticación, la llamada puede usar hasta dos subprocesos de trabajo y dos subprocesos de puerto de finalización. Por lo tanto, puede agotar la administración cuando se produzcan varias llamadas ThreadPool de servicio web al mismo tiempo.
Por ejemplo, supongamos que el número está limitado a 10 subprocesos de trabajo y que los 10 subprocesos de trabajo están ejecutando código que está esperando a que se ejecute una devolución ThreadPool de llamada. La devolución de llamada nunca se puede ejecutar, ya que los elementos de trabajo que se ponen en cola se bloquean hasta que ThreadPool un subproceso esté disponible.
Otro posible origen de contención es el parámetro que usa el espacio de nombres maxconnection para limitar el número de System.Net conexiones. Por lo general, este límite funciona según lo esperado. Sin embargo, si muchas aplicaciones intentan realizar muchas solicitudes a una sola dirección IP al mismo tiempo, es posible que los subprocesos tengan que esperar una conexión disponible.
Solución
Para resolver estos problemas, puede ajustar los siguientes parámetros en el archivoMachine.config para que se ajuste mejor a su situación:
maxWorkerThreadsminWorkerThreadsmaxIoThreadsminFreeThreadsminLocalRequestFreeThreadsmaxconnectionexecutionTimeout
Para resolver correctamente estos problemas, lleve a cabo las siguientes acciones:
- Limite el número de ASP.NET que se pueden ejecutar al mismo tiempo a aproximadamente 12 por CPU.
- Permitir que las devoluciones de llamada de servicio web usen libremente subprocesos en
ThreadPoolel . - Seleccione un valor adecuado para el
maxconnectionsparámetro. Basa la selección en el número de direcciones IP y AppDomains que se usan.
Nota
La recomendación de limitar el número de solicitudes ASP.NET a 12 por CPU es un poco arbitraria. Sin embargo, este límite ha demostrado funcionar bien para la mayoría de las aplicaciones.
MaxWorkerThreads y maxIoThreads
ASP.NET las dos opciones de configuración siguientes para limitar el número máximo de subprocesos de trabajo y subprocesos de finalización que se usan:
<processModel maxWorkerThreads="20" maxIoThreads="20">
El maxWorkerThreads parámetro y el parámetro se maxIoThreads multiplican implícitamente por el número de CPU. Por ejemplo, si tiene dos procesadores, el número máximo de subprocesos de trabajo es 2 * maxWorkerThreads .
MinFreeThreads y minLocalRequestFreeThreads
ASP.NET también contiene las siguientes opciones de configuración que determinan cuántos subprocesos de trabajo y subprocesos de puerto de finalización deben estar disponibles para iniciar una solicitud remota o una solicitud local:
<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">
Si no hay suficientes subprocesos disponibles, la solicitud se pone en cola hasta que los subprocesos suficientes sean libres para realizar la solicitud. Por lo tanto, ASP.NET no ejecutará más del siguiente número de solicitudes al mismo tiempo:
( maxWorkerThreads * número de CPU) - minFreeThreads
Nota
El parámetro y el parámetro no se multiplican minFreeThreads minLocalRequestFreeThreads implícitamente por el número de CPU.
MinWorkerThreads
ASP.NET también contiene la siguiente configuración que determina cuántos subprocesos de trabajo pueden estar disponibles inmediatamente para dar servicio a una solicitud remota.
<processModel minWorkerThreads="1">
Los subprocesos controlados por esta configuración se pueden crear a una velocidad mucho más rápida que los subprocesos de trabajo que se crean a partir de las capacidades predeterminadas de ajuste de subprocesos de Common Language Runtime (CLR).
Esta configuración permite a ASP.NET dar servicio a las solicitudes que pueden llenar repentinamente la cola de solicitudes de ASP.NET debido a una ralentización en un servidor back-end, una ráfaga repentina de solicitudes del final del cliente o algo similar que provocaría un aumento repentino del número de solicitudes en la cola.
El valor predeterminado del minWorkerThreads parámetro es 1. Se recomienda establecer el valor del minWorkerThreads parámetro en el siguiente valor:
minWorkerThreads = maxWorkerThreads / 2
De forma predeterminada, el parámetro no está presente en el archivo minWorkerThreads Web.config ni en el Machine.config archivo. Esta configuración se multiplica implícitamente por el número de CPU.
Maxconnection
El maxconnection parámetro determina cuántas conexiones se pueden realizar a una dirección IP específica. El parámetro aparece de la siguiente manera:
<connectionManagement>
<add address="*" maxconnection="2">
<add address="http://65.53.32.230" maxconnection="12">
</connectionManagement>
Si el código de la aplicación hace referencia a la aplicación por nombre de host en lugar de por dirección IP, el parámetro debe aparecer de la siguiente manera:
<connectionManagement>
<add address="*" maxconnection="2">
<add address="http://hostname" maxconnection="12">
</connectionManagement>
Por último, si la aplicación se hospeda en un puerto distinto de 80, el parámetro debe incluir el puerto no estándar en la dirección URL, de forma similar a la siguiente:
<connectionManagement>
<add address="*" maxconnection="2">
<add address="http://hostname:8080" maxconnection="12">
</connectionManagement>
La configuración de los parámetros que se han analizado anteriormente en este artículo se encuentra en el nivel de proceso. Sin embargo, maxconnection la configuración del parámetro se aplica al nivel AppDomain. De forma predeterminada, dado que esta configuración se aplica al nivel AppDomain, puede crear un máximo de dos conexiones a una dirección IP específica de cada AppDomain en el proceso.
ExecutionTimeout
ASP.NET la siguiente configuración para limitar el tiempo de ejecución de la solicitud:
<httpRuntime executionTimeout="90"/>
También puede establecer este límite mediante la Server.ScriptTimeout propiedad.
Nota
Si aumenta el valor del parámetro, es posible que también tenga que executionTimeout modificar la configuración del processModel responseDeadlockInterval parámetro.
Recomendaciones
Es posible que la configuración recomendada en esta sección no funcione para todas las aplicaciones. Sin embargo, la siguiente información adicional puede ayudarle a realizar los ajustes adecuados.
Si realiza una llamada de servicio web a una sola dirección IP desde cada página ASPX, Microsoft recomienda usar las siguientes opciones de configuración:
- Establezca los valores del
maxWorkerThreadsparámetro y el parámetro enmaxIoThreads100. - Establezca el valor del
maxconnectionparámetro en 12 * N (donde N es el número de CPU que tiene). - Establezca los valores del
minFreeThreadsparámetro en 88 * N yminLocalRequestFreeThreadsel parámetro en 76 * N. - Establezca el valor en
minWorkerThreads50. Recuerde queminWorkerThreadsno está en el archivo de configuración de forma predeterminada. Debe agregarlo.
Algunas de estas recomendaciones implican una fórmula sencilla que implica el número de CPU en un servidor. La variable que representa el número de CPU en las fórmulas es N.
Para esta configuración, si tiene habilitado el hyperthreading, debe usar el número de CPU lógicas en lugar del número de CPU físicas. Por ejemplo, si tiene un servidor de cuatro procesadores con hyperthreading habilitado, el valor de N en las fórmulas será 8 en lugar de 4.
Nota
Al usar esta configuración, puede ejecutar un máximo de 12 solicitudes ASP.NET por CPU al mismo tiempo porque 100-88=12. Por lo tanto, al menos 88 * subprocesos de trabajo N y 88 * N subprocesos de puerto de finalización están disponibles para otros usos (como para las devoluciones de llamada del servicio web).
Por ejemplo, tiene un servidor con cuatro procesadores e hiperthreading habilitados. Basándose en estas fórmulas, usaría los siguientes valores para las opciones de configuración que se mencionan en este artículo.
<system.web>
<processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
<httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608"/>
</system.web>
<system.net>
<connectionManagement>
<add address="[ProvideIPHere]" maxconnection="96"/>
</connectionManagement>
</system.net>
Además, al usar esta configuración, hay 12 conexiones disponibles por CPU por dirección IP para cada AppDomain. Por lo tanto, en el siguiente escenario, se produce muy poca contención cuando las solicitudes esperan conexiones y no ThreadPool se agota:
- La web hospeda solo una aplicación (AppDomain).
- Cada solicitud de una página ASPX realiza una solicitud de servicio web.
- Todas las solicitudes se encuentran en la misma dirección IP.
Sin embargo, al usar esta configuración, los escenarios que implican una de las siguientes opciones probablemente usarán demasiadas conexiones:
- Las solicitudes son a varias direcciones IP.
- Las solicitudes se redirigen (código de estado 302).
- Las solicitudes requieren autenticación.
- Las solicitudes se realizan desde varios AppDomains.
En estos escenarios, es buena idea usar un valor inferior para el parámetro y valores más altos maxconnection para el parámetro y el minFreeThreads minLocalRequestFreeThreads parámetro.
Más información
Para obtener más información, vea Improving ASP.NET Performance.
Si experimenta un rendimiento y una contención deficientes en IIS junto con ASP.NET, vaya a los siguientes blogs de Microsoft: