Sergio es correcto. Su aplicación, en este punto, probablemente sea mejor en el modelo tradicional de Apache/Pasajero. Si toma la ruta prevista, especialmente en plataformas de un solo subproceso como Ruby, NUNCA puede bloquear nada, ya sea la base de datos, los servidores de caché, otras solicitudes HTTP que pueda hacer, nada.
Esto es lo que hace que la programación asincrónica (evented) sea más difícil: es fácil bloquear cosas, generalmente en forma de E/S de disco síncronas o resoluciones de DNS. Los frameworks sin bloqueo (evented) tales como nodejs son cuidadosos ya que (casi) nunca le proporcionan una llamada de función de marco que bloquea, sino que todo se maneja mediante devoluciones de llamada (incluidas las consultas DB).
Esto podría ser más fácil de visualizar si nos fijamos en el corazón de un servidor de un solo subproceso no bloqueante:
while(wait_on_sockets(/* list<socket> */ &$sockets, /* event */ &$what, $timeout)) {
foreach($socketsThatHaveActivity as $fd in $sockets) {
if($what == READ) { // There is data availabe to read from this socket
$data = readFromSocket($fd);
processDataQuicklyWithoutBlocking($data);
}
elseif ($what == WRITE && $data = dataToWrite($fd)) { // This socket is ready to be written to (if we have any data)
writeToSocket($fd, $data);
}
}
}
Lo que ves arriba se llama el bucle de eventos. wait_on_sockets
suele ser proporcionado por el SO en forma de una llamada al sistema, como select, poll, epoll o kqueue. Si processDataQuicklyWithoutBlocking tarda demasiado, el búfer de red de la aplicación mantenido por el sistema operativo (solicitudes nuevas, datos entrantes, etc.) se llenará y hará que rechace conexiones nuevas y agote las existentes, ya que $ socketsThatHaveActivity no se está manejando lo suficientemente rápido . Esto es diferente de un servidor enhebrado (por ejemplo, una instalación típica de Apache) porque cada conexión se sirve utilizando un proceso/subproceso independiente, de modo que los datos entrantes se leerán en la aplicación tan pronto como lleguen, y los datos salientes se enviarán sin demora. .
Lo que las plataformas sin bloqueo como nodejs hacen cuando realiza (por ejemplo) una consulta de DB es agregar la conexión de socket del servidor de bases de datos a la lista de sockets que se monitorean ($ sockets), incluso si su consulta un tiempo, su (único) hilo no está bloqueado en ese socket. Sino que sirven de devolución de llamada:
$db.query("...sql...", function($result) { ..handle result ..});
Como se puede ver arriba, db.query vuelve inmediatamente sin ningún tipo de bloqueo en el servidor db en absoluto.Esto también significa que con frecuencia tiene que escribir código como este, a menos que el lenguaje de programación en sí es compatible con funciones asíncronas (como el nuevo C#):
$db.query("...sql...", function($result) { $httpResponse.write($result); $connection.close(); });
La regla de nunca jamás-bloque puede ser un poco relajado si tiene muchos procesos que cada uno ejecuta un bucle de eventos (generalmente la forma de ejecutar un clúster de nodos), o usa un grupo de subprocesos para mantener el bucle de eventos (embarcadero de java, netty, etc., puede escribir el suyo en C/C++). Mientras que un hilo está bloqueado en algo, otros hilos aún pueden hacer el ciclo de evento. Pero bajo una carga lo suficientemente pesada, incluso estas no funcionarían. Así que NUNCA NUNCA BLOQUEAR en un servidor con el ventilador puesto.
Como puede ver, los servidores evented generalmente intentan resolver un problema diferente: pueden tener una gran cantidad de conexiones abiertas. Donde sobresalen es simplemente empujando bytes con cálculos ligeros (por ejemplo, servidores de cometas, memorias caché como memcached, barniz, proxies como nginx, squid, etc.). No vale la pena que, aunque escalan mejor, los tiempos de respuesta generalmente tienden a aumentar (nada es mejor que reservar un hilo completo para una conexión). Por supuesto, puede que no sea económica/computacionalmente factible ejecutar la misma cantidad de subprocesos como # de conexiones simultáneas.
Ahora volviendo a su problema, recomiendo que todavía tenga Nginx, ya que es excelente en la administración de la conexión (que está basada en eventos), generalmente significa manejar HTTP keep-alives, SSL, etc. Debe conectar esto a su aplicación de Rails usando FastCGI, donde todavía necesita ejecutar trabajadores, pero no tiene que volver a escribir su aplicación para que se destaque por completo. También debe dejar que Nginx sirva contenido estático; no tiene sentido que sus trabajadores de Rails estén atados con algo que normalmente Nginx puede hacer mejor. Este enfoque generalmente se escala mucho mejor que Apache/Passenger, especialmente si ejecuta un sitio web de alto tráfico.
Si puede escribir toda su aplicación para ser descubierta, entonces genial, pero no tengo idea de cuán fácil o difícil es eso en Ruby.
Guau .. gracias por la respuesta detallada Tejas. Entonces, los puntos de referencia que leo de la red ... ¿son para un género de aplicación completamente diferente? El propio sitio de Thin ofrece una aplicación de rieles como aplicación de ejemplo para thin. http://code.macournoyer.com/thin/. Tenía la impresión de que podría reemplazar al pasajero con delgado y que todo será hortera. –
Siempre y cuando no bloquee ningún lugar, debería poder recrear esos puntos de referencia. – tejas