[ Esta publicación está actualizada a partir del 2012-09-02 (más reciente que la anterior). ]
Node.js escala absolutamente en máquinas de múltiples núcleos.
Sí, Node.js es un subproceso por proceso. Esta es una decisión de diseño muy deliberada y elimina la necesidad de lidiar con la semántica de bloqueo. Si no está de acuerdo con esto, probablemente aún no se dé cuenta de lo increíblemente difícil que es depurar el código de subprocesos múltiples. Para una explicación más profunda del modelo de proceso Node.js y por qué funciona de esta manera (y por qué NUNCA admitirá múltiples hilos), lea mi otra publicación .
Entonces, ¿cómo aprovecho mi caja de 16 núcleos?
Dos caminos:
- Para grandes tareas de cómputo pesado como la codificación de imágenes, Node.js puede iniciar procesos secundarios o enviar mensajes a procesos de trabajo adicionales. En este diseño, tendría un subproceso que administra el flujo de eventos y N procesos que realizan tareas de computación pesadas y mastican las otras 15 CPU.
- Para escalar el rendimiento en un servicio web, debe ejecutar varios servidores Node.js en un cuadro, uno por núcleo y dividir el tráfico de solicitudes entre ellos. Esto proporciona una excelente afinidad con la CPU y escalará el rendimiento casi linealmente con el recuento de núcleos.
Escalado de rendimiento en un servicio web
Desde v6.0.X Node.js ha incluido el módulo de clúster directamente, lo que facilita la configuración de múltiples trabajadores de nodo que pueden escuchar en un solo puerto. Tenga en cuenta que esto NO es lo mismo que el antiguo módulo "cluster" de learnboost disponible a través de npm .
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
Los trabajadores competirán para aceptar nuevas conexiones, y el proceso menos cargado es más probable que gane. Funciona bastante bien y puede aumentar el rendimiento bastante bien en una caja de múltiples núcleos.
Si tiene suficiente carga para preocuparse por múltiples núcleos, entonces también querrá hacer algunas cosas más:
Ejecute su servicio Node.js detrás de un proxy web como Nginx o Apache , algo que puede limitar la conexión (a menos que desee que las condiciones de sobrecarga reduzcan completamente el cuadro), reescriba URL, sirva contenido estático y delegue otros subservicios.
Recicla periódicamente tus procesos de trabajo. Para un proceso de larga duración, incluso una pequeña pérdida de memoria eventualmente se acumulará.
Configurar la recopilación / supervisión de registros
PD: Hay una discusión entre Aaron y Christopher en los comentarios de otra publicación (al momento de escribir este artículo, es la publicación principal). Algunos comentarios al respecto:
- Un modelo de socket compartido es muy conveniente para permitir que múltiples procesos escuchen en un solo puerto y compitan para aceptar nuevas conexiones. Conceptualmente, se podría pensar en Apache preformado haciendo esto con la advertencia importante de que cada proceso solo aceptará una única conexión y luego morirá. La pérdida de eficiencia para Apache está en la sobrecarga de bifurcar nuevos procesos y no tiene nada que ver con las operaciones de socket.
- Para Node.js, hacer que N trabajadores compitan en un solo socket es una solución extremadamente razonable. La alternativa es configurar un front-end en caja como Nginx y tener ese tráfico proxy para los trabajadores individuales, alternando entre trabajadores para asignar nuevas conexiones. Las dos soluciones tienen características de rendimiento muy similares. Y dado que, como mencioné anteriormente, es probable que desee tener Nginx (o una alternativa) al frente de su servicio de nodo de todos modos, la elección aquí es realmente entre:
Puertos compartidos: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)
vs
Puertos individuales: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}
Podría decirse que hay algunos beneficios para la configuración de puertos individuales (potencial para tener un menor acoplamiento entre procesos, tener decisiones de equilibrio de carga más sofisticadas, etc.), pero definitivamente es más trabajo configurarlo y el módulo de clúster incorporado es bajo alternativa de complejidad que funciona para la mayoría de las personas.