¿Por qué Node.js tiene un solo subproceso? [cerrado]

255

En servidores web basados ​​en PHP (o Java / ASP.NET / Ruby), cada solicitud de cliente se instancia en un nuevo hilo. Pero en Node.js todos los clientes se ejecutan en el mismo subproceso (¡incluso pueden compartir las mismas variables!) Entiendo que las operaciones de E / S están basadas en eventos, por lo que no bloquean el bucle del subproceso principal.

Lo que no entiendo es ¿POR QUÉ el autor de Node lo eligió para un solo subproceso? Hace las cosas difíciles. Por ejemplo, no puedo ejecutar una función intensiva de CPU porque bloquea el subproceso principal (y las nuevas solicitudes de los clientes están bloqueadas), así que necesito generar un proceso (lo que significa que necesito crear un archivo JavaScript separado y ejecutar otro proceso de nodo en eso). Sin embargo, en PHP, las tareas intensivas de la CPU no bloquean a otros clientes porque, como mencioné, cada cliente está en un hilo diferente. ¿Cuáles son sus ventajas en comparación con los servidores web multiproceso?

Nota: He usado el agrupamiento para evitar esto, pero no es bonito.

foreyez
fuente
12
Recientemente vi un buen video (29 minutos) que explica parte de la teoría detrás de Node. Incluso creo que el tipo habla sobre tareas intensivas de CPU y brevemente cómo manejarlas: youtube.com/watch?v=L0pjVcIsU6A
whirlwin
24
Puede saber esto, pero para ser claros, Node.js no tiene un solo subproceso. Su código JavaScript se ejecuta con un solo subproceso, pero las operaciones de E / S y otras cosas que los complementos pueden ejecutar se quedan sin un grupo de subprocesos. Node.js le brinda gran parte del beneficio de subprocesamiento múltiple sin tener que lidiar con código multiproceso. Además, los contribuyentes de Node.js no eligieron la naturaleza de un solo subproceso de JavaScript, sí lo hicieron los autores de JavaScript. No puedo pensar en una forma en que JS podría funcionar en un contexto multiproceso, pero incluso si lo hubiera, V8 no está escrito de esa manera, que es lo que Node.js usa como su motor de JavaScript.
Brad
55
PHP es más simple que JavaScript. Probablemente esté pensando en módulos de servidor como FastCGI o mod_php. De hecho, está comparando Node.js con Apache, Nginx o IIS, no con PHP, Java o Ruby.
Álvaro González
34
El nodo no tiene un solo subproceso. Es un concepto erróneo popular. Incluso simple node -e 'setTimeout(()=>{},1000);' & ps -T h $! | wc -l; kill $!muestra cinco hilos en mi sistema. El bucle de eventos principal es de un solo subproceso (no tendría mucho sentido si no lo fuera), pero Node tiene muchos subprocesos múltiples y puede escribir aplicaciones de un solo proceso de subprocesos múltiples si lo desea. Me encantaría escribir una respuesta integral al respecto, pero algunas personas decidieron cerrar su pregunta, por lo que no puedo. Estoy votando para reabrirlo. Si obtiene más votos y se vuelve a abrir, por favor, mencióneme en el comentario.
rsp
2
@rsp gracias por tu comentario, pero quise decir en el hilo principal no relacionado con E / S. Si está haciendo algo relacionado con la CPU, como un bucle grande que hace algo, el servidor deja de procesar las conexiones. es decir, el servidor no se puede usar en ese momento. así que nos quedamos usando hacks como clústeres solo para hacer algo tan simple en lugar de enhebrar inherentemente cada conexión como lo hacen la mayoría de los servidores. jxcore.com trató de abordar esto, pero luego hace que uno use complementos de nodo especiales / modificados, lo que esencialmente lo hace inutilizable para mí.
foreyez

Respuestas:

292

Node.js se creó explícitamente como un experimento en el procesamiento asíncrono. La teoría era que el procesamiento asíncrono en un solo subproceso podría proporcionar más rendimiento y escalabilidad bajo cargas web típicas que la implementación típica basada en subprocesos.

¿Y sabes qué? En mi opinión, esa teoría ha sido confirmada. Una aplicación node.js que no hace cosas intensivas en CPU puede ejecutar miles de conexiones simultáneas más que Apache o IIS u otros servidores basados ​​en hilos.

La naturaleza asincrónica de un solo subproceso complica las cosas. ¿Pero honestamente crees que es más complicado que enhebrar? ¡Una condición de carrera puede arruinar todo tu mes! ¡O vacíe su grupo de subprocesos debido a alguna configuración en alguna parte y observe cómo su tiempo de respuesta se ralentiza! Sin mencionar los puntos muertos, las inversiones prioritarias y todos los otros giros que van con el subprocesamiento múltiple.

Al final, no creo que sea universalmente mejor o peor; es diferente, y algunas veces es mejor y otras no. Use la herramienta adecuada para el trabajo.

Chris Tavares
fuente
26
Pero los servidores web suelen hacer MUCHAS cosas intensivas en CPU, no es SOLO la obtención de bases de datos. Necesitamos procesar lo que buscamos y hacer mucha lógica de negocios mucho tiempo antes de entregarlo al cliente.
foreyez
22
Así que solo genera trabajadores, ¡bueno! Ese es todo el trato con Node.js. Las cosas pesadas pueden ejecutarse en otro proceso, y si procesas resulta en una devolución de llamada ligera.
MaiaVictor
77
El problema con eso es que hay un proceso de nivel de sistema operativo ejecutándose por trabajador. Los verá usando el comando "ps". Eso significa potencialmente miles de procesos que se ejecutan en la máquina a la vez, ¡eso es una locura!
foreyez
99
@foreyez, no necesitas un proceso por usuario. Puede elegir cómo dividir la carga. Además, no todos están haciendo un montón de cosas intensivas en CPU. Node es una herramienta para un trabajo ... tal vez no sea su trabajo, sino muchos tipos de trabajos.
Brad
15
En realidad, me gustaría que @foreyez hiciera una copia de seguridad de esa afirmación de que "los servidores web generalmente MUCHOS (sic) de cosas intensivas en CPU". En mi experiencia, no lo hacen. O tal vez mi definición de 'CPU intensiva' difiere de la suya. La conversión de datos del producto en una interfaz de usuario no requiere mucho uso de la CPU, ni el cálculo de pedidos o similares. La mayor parte de la web es bastante transaccional. El uso intensivo de CPU es cosas como convertir videos, convertir formatos de imagen, etc. Gran parte de eso se debe a la E / S de archivo que, en realidad, el nodo funciona bastante bien. Y facilita la descarga a otro proceso dedicado a la conversión.
Paul
62

El problema con el modelo de "un subproceso por solicitud" para un servidor es que no se escalan bien para varios escenarios en comparación con el modelo de subproceso de bucle de eventos.

Por lo general, en escenarios intensivos de E / S, las solicitudes pasan la mayor parte del tiempo esperando que se complete la E / S. Durante este tiempo, en el modelo de "un subproceso por solicitud", los recursos vinculados al subproceso (como la memoria) no se utilizan y la memoria es el factor limitante. En el modelo de bucle de eventos, el hilo del bucle selecciona el próximo evento (E / S terminado) para manejar. Por lo tanto, el hilo siempre está ocupado (si lo programa correctamente, por supuesto).

El modelo de bucle de eventos como todas las cosas nuevas parece brillante y la solución para todos los problemas, pero qué modelo usar dependerá del escenario que deba abordar. Si tiene un escenario de E / S intensivo (como un proxy), el modelo base de eventos gobernará, mientras que un escenario intensivo de CPU con un bajo número de procesos concurrentes funcionará mejor con el modelo basado en subprocesos.

En el mundo real, la mayoría de los escenarios estarán un poco en el medio. Deberá equilibrar la necesidad real de escalabilidad con la complejidad del desarrollo para encontrar la arquitectura correcta (por ejemplo, tener un front-end de base de eventos que delegue en el back-end para las tareas intensivas de la CPU. El front-end usará pocos recursos esperando la tarea resultado.) Al igual que con cualquier sistema distribuido, requiere un poco de esfuerzo para que funcione.

Si está buscando la bala de plata que se ajuste a cualquier escenario sin ningún esfuerzo, terminará con una bala en su pie.

Kazaag
fuente
8
Node.js está restringido al procesamiento de solo eventos debido a la falta de compatibilidad con subprocesos múltiples v8. Bueno, el lenguaje javascript carece de las características necesarias, por lo que cualquier implementación terminará siendo complicada. Ese es el principal culpable de Node.js, en mi opinión. En otros idiomas puedes elegir lo que quieras. O algún híbrido de ambos modelos, como java NIO.
FrameGrace
2
@Kazaag, servidores web modernos hacen mantener una subprocesos. No solo generan tontamente un nuevo hilo por carga de página. Esos son los servidores web más antiguos.
Pacerier
1
@Pacerier Nunca dije que se genera un nuevo subproceso, pero cada subproceso se asigna a una solicitud hasta que finalice la solicitud.
Kazaag
2
@Kazaag Definitivamente no es una regla general que "cada subproceso se asigna a una solicitud hasta que finalice la solicitud". Es decir, en .Net (incluido el procesamiento de solicitudes HTTP) uno puede y debe usar programación asincrónica (basada en tareas) y esto liberará hilos mientras espera que se completen las operaciones de E / S y otras operaciones asincrónicas. Esto también es aplicable a la programación de alto nivel, es decir, controladores MVC / API. Entonces, en la práctica, podría haber 20 solicitudes HTTP pendientes, pero solo un hilo activo.
user3285954
29

En pocas palabras, el nodo se basa en V8, que tiene un solo subproceso interno. Hay formas de evitar las restricciones para las tareas intensivas de CPU.

En un momento (0.7), los autores intentaron introducir aislamientos como una forma de implementar múltiples hilos de cálculo, pero finalmente fueron eliminados: https://groups.google.com/forum/#!msg/nodejs/zLzuo292hX0/F7gqfUiKi2sJ

SheetJS
fuente
¿Tiene más información sobre este "aislamiento"?
Pacerier