¿Qué está limitando el número de conexiones simultáneas que mi aplicación ASP.NET puede realizar a un servicio web?

90

Tengo una aplicación ASP.NET 4.0 que se ejecuta sobre IIS 7.5 en una máquina Windows Server 2008 R2 Enterprise de 64 bits con mucha RAM, CPU, disco, etc.

Con cada solicitud web, la aplicación ASP.NET establece una conexión a un servicio web backend (a través de sockets sin procesar), que se ejecuta en la misma máquina.

Problema: parece haber algo que limita el número de conexiones simultáneas al servicio web de backend. Sospechosamente, la cantidad de conexiones simultáneas llega a 16.

Encontré este artículo clave de Microsoft que explica cómo modificar la configuración de IIS para adaptarse a las aplicaciones ASP.NET que realizan muchas solicitudes de servicios web: http://support.microsoft.com/?id=821268#tocHeadRef

Seguí las recomendaciones del artículo, pero aún no tuve suerte. El escenario que es particularmente interesante es el maxconnectionescenario, que incluso salté a 999.

¿Alguna idea de qué más podría estrangular las conexiones?

Nota: Cuando elimino IIS de la mezcla y hago que los clientes se conecten directamente al servicio web de backend, felizmente abrirá tantas conexiones como necesite, así que estoy seguro de que el backend no es el cuello de botella. Debe ser algo en IIS / ASP.NET-land.

Aquí está la sección relevante de la machine.configque estoy seguro que está siendo leída por la aplicación (verificada con appcmd.exe):

<system.web>
    <processModel autoConfig="false" maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50" />
    <httpRuntime minFreeThreads="176" minLocalRequestFreeThreads="152"/>

    <httpHandlers />

    <membership>
        <providers>
            <add name="AspNetSqlMembershipProvider"
                type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                connectionStringName="LocalSqlServer"
                enablePasswordRetrieval="false"
                enablePasswordReset="true"
                requiresQuestionAndAnswer="true"
                applicationName="/"
                requiresUniqueEmail="false"
                passwordFormat="Hashed"
                maxInvalidPasswordAttempts="5"
                minRequiredPasswordLength="7"
                minRequiredNonalphanumericCharacters="1"
                passwordAttemptWindow="10"
                passwordStrengthRegularExpression="" />
        </providers>
    </membership>

    <profile>
        <providers>
            <add name="AspNetSqlProfileProvider" connectionStringName="LocalSqlServer" applicationName="/"
                type="System.Web.Profile.SqlProfileProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </providers>
    </profile>

    <roleManager>
        <providers>
            <add name="AspNetSqlRoleProvider" connectionStringName="LocalSqlServer" applicationName="/"
                type="System.Web.Security.SqlRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
            <add name="AspNetWindowsTokenRoleProvider" applicationName="/"
                type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </providers>
    </roleManager>
</system.web>
<system.net>
    <connectionManagement>
        <add address="*" maxconnection="999"/>
    </connectionManagement>
</system.net>
Rob Sobers
fuente
@DanB tiene un buen punto aquí: ¿cómo está midiendo la cantidad de conexiones simultáneas?
Jeremy McGee
@JeremyMcGee Estoy midiendo el número de conexiones simultáneas ejecutando TCPView en el servidor para ver cuántas conexiones backend realizan los procesos de trabajo de IIS.
Rob Sobers
¿Los clientes web se ejecutan en máquinas independientes o en la misma máquina? (Comprobando que no haya ninguna limitación del lado del cliente)
Jeremy McGee
3
@JeremyMcGee Máquinas separadas. 1 conexión cliente-servidor por máquina. Además, sabemos que no hay ninguna limitación en algún lugar de la red porque cuando accedemos directamente al backend (lo que también ocurre a través de HTTP) no nos encontramos con el cuello de botella.
Rob Sobers
1
Rob, ¿alguna vez encontraste una solución definitiva a esto?
electronicKT

Respuestas:

104

La mayoría de las respuestas proporcionadas aquí abordan la cantidad de solicitudes entrantes a su servicio web backend, no la cantidad de solicitudes salientes que puede realizar desde su aplicación ASP.net a su servicio backend.

No es su servicio web backend el que está limitando su tasa de solicitud aquí, es la cantidad de conexiones abiertas que su aplicación de llamadas está dispuesta a establecer al mismo punto final (misma URL).

Puede eliminar esta limitación agregando la siguiente sección de configuración a su archivo machine.config:

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

Por supuesto, puede elegir un número más razonable si lo desea, como 50 o 100 conexiones simultáneas. Pero lo anterior lo abrirá hasta el máximo. También puede especificar una dirección específica para la regla de límite de apertura anterior en lugar del '*' que indica todas las direcciones.

Documentación de MSDN para System.Net.connectionManagement

Otro gran recurso para comprender ConnectManagement en .NET

¡Espero que esto resuelva tu problema!

EDITAR: Vaya, veo que tiene la administración de conexión mencionada en su código anterior. Dejaré mi información anterior ya que es relevante para futuros usuarios con el mismo problema. Sin embargo, tenga en cuenta que actualmente hay 4 archivos machine.config diferentes en la mayoría de los servidores actualizados.

Hay .NET Framework v2 que se ejecuta en 32 y 64 bits, así como .NET Framework v4 también se ejecuta en 32 y 64 bits. Dependiendo de la configuración elegida para su grupo de aplicaciones, ¡podría estar usando cualquiera de estos 4 archivos machine.config diferentes! Compruebe los 4 archivos machine.config que normalmente se encuentran aquí:

  • C: \ Windows \ Microsoft.NET \ Framework \ v2.0.50727 \ CONFIG
  • C: \ Windows \ Microsoft.NET \ Framework64 \ v2.0.50727 \ CONFIG
  • C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Config
  • C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ Config
BenSwayne
fuente
Sí, cubrí esa base. ¡Gracias de todos modos, @BenSwayne! Verifiqué que modifiqué el correcto machine.config(64 bits 4.0).
Rob Sobers
@RobSobers: En este caso, sospecharía un poco del código de implementación. ¿Quizás te estás quedando sin hilos o algo así? ¿Puede lanzar su código de llamada de servicio web TcpClient en una aplicación de consola y ver si puede lograr una mejor tasa de solicitud? Esto demostrará si es una configuración específica de IIS o una configuración .NET más amplia o su código.
BenSwayne
¿Esta línea va en la máquina cliente?
Uri Abramson
gracias, su configuración se combina con processModel twekaing de codeproject.com/Articles/133738/ ... fijo "ISAPI 'C: \ windows \ Microsoft.Net \ Framework \ v2.0.050727 \ aspnet_isapi.dll' se reportó como insalubre por el siguiente motivo : Problema de "
interbloqueo
@BenSwayne, ¿el mismo concepto se aplica también a las conexiones SMTP? Estoy diseñando una aplicación de envío de correo electrónico masivo, por lo que esta propiedad ConnectionManagement también será útil para enviar correos masivos (usando múltiples subprocesos para la función mail.send ).
vibs2006
7

Me doy cuenta de que la pregunta puede ser bastante antigua, pero usted dice que el backend se ejecuta en el mismo servidor. Eso significa en un puerto diferente, probablemente diferente al puerto predeterminado 80.

Leí que cuando usa el elemento de configuración "connectionManagement", debe especificar el número de puerto si difiere del 80 predeterminado.

ENLACE: la configuración de maxConnection puede no funcionar incluso autoConfig = false en ASP.NET

En segundo lugar, si elige usar la configuración predeterminada (dirección = "*") extendida con su propio valor específico de backend, ¡podría considerar poner el valor específico primero! De lo contrario, si se realiza una solicitud, el * coincide primero y se toma el valor predeterminado de 2 conexiones. Al igual que cuando usa la sección en web.config.

ENLACE: <remove> Elemento para la gestión de conexiones (Configuración de red)

Espero que ayude a alguien.

Sebastián Hek
fuente
5

¿Es posible que esté utilizando una referencia de servicio web basada en WCF? De forma predeterminada, ServiceThrottlingBehavior.MaxConcurrentCalls es 16.

Podría intentar actualizar el <serviceThrottling>elemento de comportamiento de referencia de su servicio

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

(Tenga en cuenta que recomendaría la configuración anterior). Consulte MSDN para obtener más información sobre cómo configurar un <behavior>elemento apropiado .

Ruben
fuente
Ojalá lo estuviéramos, pero no lo somos. El servicio que se consume se ejecuta en Apache / Python / mod_wsgi en otra máquina y, como dijo Rob, claramente no es el problema.
Benjamin Pollack
Las referencias de servicio están en el cliente. ¿Cómo consume su cliente el servicio Apache?
John Saunders
Como dijo John: la limitación se establece en el cliente que consume el servicio web. Quizás la frase "su comportamiento de servicio" sea un poco engañosa. ¿Tiene más sentido cuando se expresa como "su comportamiento de referencia de servicio"?
Ruben
@john Se consume a través de un TcpClient(el servicio vende blobs binarios personalizados, no WCF / SOAP o similar). Esas opciones de configuración parecen afectarle puramente si usa ServiceHost, no TcpClient; ¿Me estoy perdiendo de algo?
Benjamin Pollack
¿Por qué no utilizar "Agregar referencia de servicio"?
John Saunders
3

¿Ha intentado establecer el valor de la propiedad estática DefaultConnectionLimit mediante programación?

Aquí hay una buena fuente de información sobre ese verdadero dolor de cabeza ... Uso de subprocesos de ASP.NET en IIS 7.5, IIS 7.0 e IIS 6.0 , con actualizaciones para el marco 4.0.

Simon Mourier
fuente
Imagino que esto no debería importar, pero lo intentaré de todos modos.
Rob Sobers
Así es como lo arreglamos hace unos años. Tuvimos problemas de concurrencia y esto pareció aclararlo. Net.ServicePointManager.DefaultConnectionLimit = 1000 es lo que usamos. Debe configurarlo ANTES de crear clases de conexión.
Brain2000
2

Consulte la sección "Subprocesamiento" de esta página: http://msdn.microsoft.com/en-us/library/ff647786.aspx , junto con la sección "Conexiones".

¿Ha intentado aumentar el atributo maxconnection de su configuración processModel?

Matt Evans
fuente
Sí tengo. Pero ese artículo que citó señala algo interesante que ningún otro artículo sobre el tema omitió mencionar: que el maxconnectionatributo no se aplica a las llamadas de servicios web locales . En este caso particular el servicio web es local, pero tenemos ese mismo problema en otro entorno donde el servicio no es local.
Rob Sobers
@RobSobers: creo que el enlace anterior merece una segunda mirada. Verifique la parte sobre minLocalRequestFreeThreads: este proceso de trabajo usa esta configuración para poner en cola las solicitudes de localhost (donde una aplicación web llama a un servicio web en el mismo servidor ) si el número de subprocesos disponibles en el grupo de subprocesos cae por debajo de este número. Esta configuración es similar a minFreeThreads, pero solo se aplica a las solicitudes que usan localhost .
Ahmad
@Ahmad Sí, también configuré minLocalRequestFreeThreads(ver mi machine.configen la pregunta.
Rob Sobers
0

Si no está definido en el servicio web, la aplicación o el servidor (apache o IIS) que aloja el consumible del servicio web, puede crear infinitas conexiones hasta que falle

Frank Tudor
fuente
0

mientras hago las pruebas de rendimiento, la medida que sigo es RPS, es decir, cuántas solicitudes por segundo puede atender el servidor dentro de una latencia aceptable.

teóricamente, un servidor solo puede ejecutar tantas solicitudes al mismo tiempo como cantidad de núcleos en él.

No parece que el problema sea el modelo de subprocesamiento de ASP.net, ya que potencialmente puede servir miles de rps. Parece que el problema podría ser tu aplicación. ¿Está utilizando primitivas de sincronización?

también cuál es la latencia en sus servicios web, si responden muy rápido (en microsegundos), si no es así, es posible que desee considerar las llamadas asincrónicas, para que no termine bloqueando

Si esto no sirve de nada, entonces es posible que desee perfilar su código usando Visual Studio o Redgate Profiler.

np-hard
fuente