¿Cómo evitar que los problemas de los usuarios sean conviertan en nuestros?

Como comentamos en el post anterior, un usuario lento puede impactarnos en el numero de usuarios que podemos soportar en un momento dado. El usuario lento o malintencionado está explotando el hecho que la mayoría de servidores Web usan un «hijo» por conexión, y la gestión de estos hijos es costosa computacionalmente hablando.
Así que la mejor forma que tenemos para soportar muchísimos usuarios, lentos o no, es separar la gestión de la conexión de la generación del objeto a entregar.
Y como no podría ser de otra forma, tenemos de todo, desde opciones radicales en cada extremo hasta soluciones híbridas que intentan ofrecer lo mejor de los dos mundos.

En un extremo tenemos los puramente basados en una relación 1:1 entre conexión e hijo, donde tratan igual las peticiones rápidas de cálculo (ficheros estáticos) que las lentas (peticiones a base de datos, generación de html personalizados, etc). Aquí tendríamos a nuestros amigos Apache HTTP Server, Apache Tomcat y muchísimos otros basados en ellos. En estos una saturación de los «pocos» hijos disponibles nos tira el servicio tanto para ficheros estáticos como para los dinámicos.
En el otro extremos tenemos los que los hijos no son función de las conexiones existentes sino de por ejemplo los procesadores de la máquina u otros datos de valor fijo. Estos utilizan herramientas como epoll,  kqueue y la mayoría están inspirados por el problema de las 10.000 conexiones concurrentes. Casi todos estos en el fondo hacen «poquito» ya que no pueden ejecutar procedimientos complejos sin separar la ejecución mediante Threads o procesos. Como hacen «poquito» la mayoría de veces se acaban montando como frontends de los que si que hacen algo aunque en algunos casos estan diseñado para entregar ficheros. En los puramente frontend por ejemplo tendríamos al Zeus ZXTM,un gran acelerador de aplicaciones al que recomiendo dar un vistazo y luego los «web servers» como los nginx,lighttpd, que aparte de mover conexiones y modificar lo entregado al usuario de varias formas (gzip, cache, rewrites, bandwidth shaping, etc) también saben entregar ficheros y hablan FastCGI o CGI donde aquí si que irán lanzando procesos más o menos eficientemente.
Y los últimos, los híbridos, que he puesto en este saco todos los que tratan por un lado las conexiones simples mediante herramientas no bloqueantes (poll, events, etc…), y que si se encuentran una petición dinámica la pasan a un worker thread (dentro o fuera de su proceso) de forma que las peticiones a ficheros estáticos no te molestan en los workers y mirando Webs aleatorias, tendríamos una relación de 50:1 entre ficheros estáticos (js, css, imágenes, vídeos, etc) y dinámicos (la mayoría de veces el html y punto). En este saco tenemos los IIS 6, 7 y 7.5, Glassfish con Grizzly o Resin Pro, que de forma «natural» usan funcionalidades del sistema operativo para tratar las conexiones (en el fondo búfferes) de modo paralelo y cuando les llega algo «raro» lo suben a un Thread de worker, IIS con el ASP.net, Glassfish en Java y Resin en Java y PHP.
En el fondo se comportan como uno de los «puros» escalables más un daemon funcionando en FastCGI como podría ser PHP, que por defecto lanza «sólo» 8 procesos que depende de la aplicación serán suficientes o no (si estos PHP lanzan consultas a Facebook que tardan un segundo, como mucho tendrás 8 peticiones/segundo y la CPU al 100% de idle!). Pero si que te ahorras todo el tiempo de espera en la descarga del documento si les has asignado suficiente profundidad de búfer, claro 😛
En el fondo, en muchos casos no es tan importante como funciona el servidor de aplicaciones ya que en aplicaciones con bastantes usuarios requeriremos de un balanceador y ya que estamos mejor meter un ZXTM o un nginx, activarle cache y dotarle de parte de inteligencia como gzip, rewrites, validación de parámetros, etc y dejar a los servidores de aplicación trabajar sólo para la aplicación y optimizarlos para ella (memoria, threads, etc)
Teniendo en cuenta todo esto podemos llegar a aprovechar mucho más el servidor, cosa que implica, más usuarios por menos euros :D. 
Es una tontería pero monitorizar servidores en base a «load avg.» aunque es una métrica importante, nos indica que el servidor está esperando algo y no sirviendo a usuarios y si además el % de idle es alto, indica que tenemos mucho a mejorar a nivel de arquitectura, tanto de HW como SW
Bueno, diría que para hoy ya estamos, que sino me voy alargando y salen posts kilométricos
Saludos!
<update>: Ayer, antes de empezar la segunda sesión, un Senior Researcher del BSC/CNS que había realizado la tesis sobre escalabilidad en Web Servers me comentó que Tomcat lo podríamos considerar «híbrido» ya que tenemos un conector HTTP que utiliza NIO en lugar de multiples Threads, así que de los grandes sólo nos queda Apache que no soporta NIO…</update>

PS: Para aquellos que se están diciendo, es que yo quiero controlar los accesos a mis imágenes, vídeos, etc y claro los hago pasar por el PHP, plantearos un sistema de tickets o tokens que sea fácil de validar (nada de base de datos) y se lo dejáis al balanceador o frontend, os ahorrareis un montón de accesos al servidor de aplicaciones.