Tengo un servicio web WCF basado en el método JSON y POST que tiene una función llamada sitio web. Esta función tiene un código simple y solo llama a otro servicio web usando el siguiente código:

        using (var cli = new MyWebClient())
        {                
            Task<string> t = cli.UploadStringTaskAsync(myURI, "POST", request);
            if (t == await Task.WhenAny(t, Task.Delay(400)))
            {
                response = t.Result;
            }
            else
            {
                response = "";
            }
            cli.Dispose();
        }

Y la clase MyWebClient se implementa como:

class MyWebClient : WebClient
        {
            protected override WebRequest GetWebRequest(Uri address)
            {
                WebRequest request = base.GetWebRequest(address);
                if (request is HttpWebRequest)
                {
                    (request as HttpWebRequest).KeepAlive = true;                    
                    (request as HttpWebRequest).ContentType = "application/json";
                }
                return request;
            }
        }

El problema es que puedo ver en IIS que una gran cantidad de solicitudes permanecen abiertas más de 18 segundos e incluso más para 1 o 2 de mis procesos de trabajo (como puedes ver en la imagen adjunta de uno de ellos) !!! Y esto hace que el servicio sea muy lento. Tenga en cuenta que este servicio tiene alrededor de 2K solicitudes por segundo y el grupo de aplicaciones de este servicio tiene un jardín web que contiene 12 procesos de trabajo y el límite de cola es 10K. Esta situación ocurre cuando hay (por ejemplo) 4 procesos de trabajo trabajando en un tiempo predecible (alrededor de 450 ms) e IIS muestra que el tiempo máximo transcurrido en sus solicitudes es de alrededor de 380.

una gran cantidad de solicitudes que permanecen abiertas en el IIS

Tenga en cuenta que he usado cli.UploadStringTaskAsync y, por lo tanto, el tiempo de espera no se considera para cli. Entonces, tengo que implementar un código como t == await Task.WhenAny(t, Task.Delay(400)) para simular el tiempo de espera.

¿Cuál es el problema que crees? ¿El uso de await causa muchos cambios de contexto y las solicitudes se ponen en cola para ser ejecutadas por la CPU?


Editar:

Aquí puede encontrar algunas recomendaciones útiles, pero nadie puede ayudar y resolver el problema. Los configuré en la configuración web de mi aplicación, pero no pudo resolver mi problema.


Actualización:

Como información adicional, tenga en cuenta que la tarjeta de red es 1G, y como máximo tenemos un uso de ancho de banda de 100Mgb / s. Hay 6 núcleos y 12 procesadores lógicos de Intel Xeon E5-1650 V3 3.5 Ghz. Tenemos 128 GB de RAM y 480 GB de SSD.

3
Alireza Mahmoudi 11 dic. 2016 a las 19:31

1 respuesta

La mejor respuesta

Encontré una solución que resuelve el problema. El punto clave fue "ProcessModel Element (ASP.NET Settings Schema)". Como mencioné en mi pregunta:

Esta situación ocurre cuando hay (por ejemplo) 4 procesos de trabajo trabajando en un tiempo predecible (alrededor de 450 ms) e IIS muestra que el tiempo máximo transcurrido en sus solicitudes es de alrededor de 380.

Entonces, creo que equilibrar la carga entre los procesos de trabajo podría ser el problema. Al configurar el elemento processModel manualmente, resolví el problema. Después de investigar mucho, encontré este < / a> enlace valioso sobre el elemento processModel y sus propiedades.

También este enlace describe todas las propiedades y el efecto de cada elemento. Como se menciona en este enlace, hay 2 propiedades importantes llamadas "requestLimit" y "requestQueueLimit":

requestQueueLimit : especifica el número de solicitudes que se permiten en la cola antes de que ASP.NET comience a devolver el mensaje "503 - Server Too Busy" a nuevas solicitudes. El valor predeterminado es 5000.

requestLimit : especifica la cantidad de solicitudes permitidas antes de que ASP.NET lance automáticamente un nuevo proceso de trabajo para reemplazar el actual. El valor predeterminado es Infinito.

La solución es controlar y limitar requestLimit por un número racional, por ejemplo 300 en mi caso. Además, limitar requestQueueLimit mediante la multiplicación del número de procesos de trabajo y requestLimit . He aumentado el número de procesos de trabajo a 20 y, con esta configuración, se pueden poner en cola 6000 solicitudes por completo y cada proceso de trabajo tiene 300 solicitudes como máximo. Al llegar a 300 solicitudes por proceso de trabajo, ASP.NET lanza automáticamente un nuevo proceso de trabajo para tomar el lugar del actual.

Entonces, la carga se equilibra mejor entre los procesos de trabajo. ¡He revisado todas las colas y no hay ninguna solicitud con más de 400 horas transcurridas!

Creo que esta solución podría usarse como un algoritmo de balanceador de carga semi para IIS y procesos de trabajo jugando con estas propiedades ( requestLimit , requestQueueLimit y número de procesos de trabajo ).

2
Alireza Mahmoudi 12 dic. 2016 a las 12:07