Tenemos una API que se implementa utilizando ServiceStack que está alojado en IIS. Al realizar pruebas de carga de la API, descubrimos que los tiempos de respuesta son buenos, pero que se deterioran rápidamente tan pronto como llegamos a unos 3.500 usuarios simultáneos por servidor. Tenemos dos servidores y cuando los conectamos con 7,000 usuarios, los tiempos de respuesta promedio se sitúan por debajo de los 500 ms para todos los puntos finales. Los cuadros están detrás de un equilibrador de carga, por lo que obtenemos 3.500 concurrentes por servidor. Sin embargo, tan pronto como aumentamos el número total de usuarios concurrentes, vemos un aumento significativo en los tiempos de respuesta. El aumento de los usuarios concurrentes a 5,000 por servidor nos da un tiempo de respuesta promedio por punto final de alrededor de 7 segundos.
La memoria y la CPU en los servidores son bastante bajas, tanto mientras los tiempos de respuesta son buenos como cuando se deterioran. En el pico con 10,000 usuarios simultáneos, el promedio de CPU es inferior al 50% y la RAM se ubica alrededor de 3-4 GB de 16. Esto nos deja pensando que estamos llegando a algún tipo de límite en alguna parte. La siguiente captura de pantalla muestra algunos contadores clave en perfmon durante una prueba de carga con un total de 10,000 usuarios simultáneos. El contador resaltado es solicitudes / segundo. A la derecha de la captura de pantalla, puede ver que el gráfico de solicitudes por segundo se vuelve realmente errático. Este es el indicador principal para tiempos de respuesta lentos. Tan pronto como vemos este patrón, notamos tiempos de respuesta lentos en la prueba de carga.
¿Cómo hacemos para solucionar este problema de rendimiento? Estamos tratando de identificar si esto es un problema de codificación o un problema de configuración. ¿Hay alguna configuración en web.config o IIS que pueda explicar este comportamiento? El grupo de aplicaciones ejecuta .NET v4.0 y la versión de IIS es 7.5. El único cambio que hemos realizado desde la configuración predeterminada es actualizar el valor de la longitud de la cola del grupo de aplicaciones de 1,000 a 5,000. También hemos agregado la siguiente configuración al archivo Aspnet.config:
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
Más detalles:
El propósito de la API es combinar datos de varias fuentes externas y devolver como JSON. Actualmente está utilizando una implementación de caché InMemory para almacenar en caché las llamadas externas individuales en la capa de datos. La primera solicitud a un recurso obtendrá todos los datos requeridos y cualquier solicitud posterior para el mismo recurso obtendrá resultados de la memoria caché. Tenemos un 'corredor de caché' que se implementa como un proceso en segundo plano que actualiza la información en el caché a ciertos intervalos establecidos. Hemos agregado bloqueo alrededor del código que obtiene datos de los recursos externos. También hemos implementado los servicios para obtener los datos de las fuentes externas de forma asíncrona, de modo que el punto final solo sea tan lento como la llamada externa más lenta (a menos que tengamos datos en el caché, por supuesto). Esto se hace usando la clase System.Threading.Tasks.Task.¿Podríamos estar llegando a una limitación en términos de número de hilos disponibles para el proceso?