Suponga que Ud. tiene un proceso “long running” (que tarda más de lo que el usuario está dispuesto a esperar), que se dispara desde una página, la cual se sirve desde un Web Role en Windows Azure. Allá por el 2004/2005, Microsoft recomendaba utilizar ThreadPool.QueueUserWorkItem, o en el mejor de los casos, utilizar IAsyncResult. En esa época, ASP.NET era utilizado principalmente para aplicaciones de Intranet, por lo que los threads no se agotaban fácilmente.
Estas dos “soluciones” poseían los siguientes inconvenientes:
- ThreadPool.QueueUserWorkItem consumía un thread del ThreadPool. Resulta que ASP.NET usa el mismo ThreadPool por lo que ambos compiten por los mismos threads, reduciendo la cantidad de páginas que puede servir por unidad de tiempo.
- IAsyncResult permitía al programador crear sus propios threads, sin competir con ASP.NET. El problema de este diseño es que la cantidad de threads que se pueden crear es ilimitada, por lo que se puede saturar fácilmente el CPU.
Ambos problemas limitan fuertemente la capacidad de servir páginas en alta demanda.
La solución
- Evite crear Threads desde los Web Roles. Es preferible demorar ese pedido de la página o realizarlo mediante AJAX.
- Imagine que 100 solicitudes concurrentes (100 usuarios pidiendo la página) requieren 200 threads, por lo que estaría pagando el doble en costo de CPU de servidores en Web Role.
- Si el pedido es lo suficientemente largo, y se toleran demoras de unos pocos segundos desde que se envía hasta que se procesa, hágalo mediante Queues (colas) y Worker Roles. Eugenio Pace escribió una serie de artículos en Inglés (1, 2, 3) que explican la teoría y la práctica de cómo se procesa.
- La ventaja más importante es que la cantidad de servidores es regulable, no por el pico de demanda de páginas sino por la demora que estemos dispuestos a ofrecer. Haciendo números, si el promedio de solicitudes por segundo (traducidos a mensajes a la cola) es de 200 con un pico de 1000, si cada servidor maneja 100 solicitudes por segundo, debería alcanzar con 2 servidores para sostener el promedio, pero la latencia en hora pico sería quizás prohibitiva. Agregando servidores mejoraría la respuesta en hora pico; incluso puedo hacer esto de forma automatizada y dinámica.
- Si está diseñando la aplicación desde un principio, considere un diseño pensando en CQRS, el cual contempla más que los long running processes :)
Espero que les sea útil.
Gabriel