javascript - thread - nodejs worker
Node.js en máquinas multi-core (15)
Node.js parece interesante, PERO debo perderme algo, ¿no está Node.js sintonizado solo para ejecutarse en un solo proceso y subproceso?
Entonces, ¿cómo se puede escalar para CPUs multi-core y servidores multi-CPU? Después de todo, es fantástico hacer que el servidor de un solo subproceso sea lo más rápido posible, pero para cargas elevadas me gustaría usar varias CPU. Y lo mismo se aplica para hacer que las aplicaciones sean más rápidas. Parece que hoy en día, la forma es usar varias CPU y paralelizar las tareas.
¿Cómo encaja Node.js en esta imagen? ¿Es su idea distribuir de alguna manera múltiples instancias o qué?
[ Esta publicación está actualizada a partir del 2012-09-02 (más reciente que la anterior). ]
Node.js absolutamente hace escala en máquinas multi-core.
Sí, Node.js es un hilo 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, es probable que todavía 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 detallada del modelo de proceso Node.js y por qué funciona de esta manera (y por qué NUNCA soportará múltiples subprocesos), lea mi otra publicación .
Entonces, ¿cómo puedo aprovechar mi caja de 16 núcleos?
Dos caminos:
- Para tareas pesadas de gran envergadura 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 gestiona el flujo de eventos y N procesos que realizan tareas de cómputo 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 de 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 de forma inmediata, lo que facilita la configuración de varios trabajadores de nodo que pueden escuchar en un solo puerto. Tenga en cuenta que este NO es el mismo que el módulo anterior "cluster" de npm 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 es probable que el proceso con menos carga gane. Funciona bastante bien y puede escalar el rendimiento bastante bien en una caja de múltiples núcleos.
Si tiene suficiente carga para preocuparse por los 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 acelerar el proceso de conexión (a menos que desee que las condiciones de sobrecarga bajen el cuadro por completo), vuelva a escribir las URL, sirva contenido estático y genere otros sub-servicios.
Recicle periódicamente sus procesos de trabajo. Para un proceso de larga duración, incluso una pequeña pérdida de memoria eventualmente se acumulará.
Configuración de la recopilación de registros / monitoreo
PD: Hay una discusión entre Aaron y Christopher en los comentarios de otra publicación (a partir de este escrito, es la publicación principal). Algunos comentarios sobre eso:
- 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 que Apache preforzado hizo esto con la importante advertencia de que cada proceso solo aceptará una conexión y luego morirá. La pérdida de eficiencia para Apache está en la sobrecarga de forzar nuevos procesos y no tiene nada que ver con las operaciones de socket.
- Para Node.js, tener a N trabajadores compitiendo en un solo socket es una solución extremadamente razonable. La alternativa es configurar un front-end en la caja como Nginx y tener ese tráfico de proxy para los trabajadores individuales, alternando entre los 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 a 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 los puertos individuales (es posible que tenga menos acoplamiento entre procesos, que tenga decisiones más sofisticadas de balanceo de carga, etc.), pero definitivamente es más trabajo de configurar y el módulo de clúster incorporado es bajo. - Alternativa de complejidad que funciona para la mayoría de las personas.
Como se mencionó anteriormente, Cluster escalará y equilibrará la carga de su aplicación en todos los núcleos.
añadiendo algo como
cluster.on(''exit'', function () {
cluster.fork();
});
Se reiniciará los trabajadores que fallan.
En estos días, mucha gente también prefiere github.com/Unitech/pm2 , que maneja el agrupamiento por usted y también proporciona algunas características de supervisión interesantes .
Luego, agregue Nginx o HAProxy delante de varias máquinas que se ejecutan con clústeres y tendrá múltiples niveles de conmutación por error y una capacidad de carga mucho mayor.
El nuevo chico en el bloque aquí es "Up" LearnBoost.
Proporciona "recargas de tiempo de inactividad cero" y, además, crea múltiples trabajadores (de forma predeterminada, la cantidad de CPU, pero es configurable) para proporcionar el mejor de todos los mundos.
Es nuevo, pero parece ser bastante estable, y lo estoy usando felizmente en uno de mis proyectos actuales.
Es posible escalar NodeJS a múltiples cajas utilizando un equilibrador de carga TCP puro (HAProxy) delante de múltiples cajas que ejecutan un proceso de NodeJS cada una.
Si luego tiene algo de conocimiento común para compartir entre todas las instancias, puede usar una tienda central de Redis o similar a la que se pueda acceder desde todas las instancias de proceso (por ejemplo, desde todas las cajas)
Estoy usando Node worker para ejecutar procesos de una manera simple desde mi proceso principal. Parece estar funcionando muy bien mientras esperamos que llegue la forma oficial.
La versión futura de node le permitirá vincular un proceso y pasarle mensajes, y Ryan ha declarado que quiere encontrar una manera de compartir también los manejadores de archivos, por lo que no será una implementación directa de Web Worker.
En este momento no hay una solución fácil para esto, pero aún es muy temprano y node es uno de los proyectos de código abierto que se han movido más rápido, así que espere algo increíble en el futuro cercano.
Multi-nodo aprovecha todos los núcleos que pueda tener.
Eche un vistazo a http://github.com/kriszyp/multi-node .
Para necesidades más simples, puede iniciar múltiples copias del nodo en diferentes números de puerto y colocar un equilibrador de carga delante de ellos.
Node Js es compatible con la agrupación en clústeres para aprovechar todas las ventajas de su CPU. Si no lo está ejecutando con clúster, probablemente esté perdiendo las capacidades de su hardware.
La agrupación en clúster en Node.js le permite crear procesos separados que pueden compartir el mismo puerto de servidor. Por ejemplo, si ejecutamos un servidor HTTP en el puerto 3000, es un servidor que se ejecuta en un solo hilo en un solo núcleo del procesador.
El código que se muestra a continuación le permite agrupar su aplicación. Este código es un código oficial representado por Node.js.
var cluster = require(''cluster'');
var numCPUs = require(''os'').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
Object.keys(cluster.workers).forEach(function(id) {
console.log("I am running with ID : " + cluster.workers[id].process.pid);
});
cluster.on(''exit'', function(worker, code, signal) {
console.log(''worker '' + worker.process.pid + '' died'');
});
} else {
//Do further processing.
}
Revisa este artículo para el tutorial completo
Puede ejecutar su aplicación node.js en múltiples núcleos utilizando el módulo de cluster en combinación con el módulo os , que puede usarse para detectar cuántas CPU tiene.
Por ejemplo, imaginemos que tiene un módulo de server
que ejecuta un servidor http simple en el backend y desea ejecutarlo para varias CPU:
// Dependencies.
const server = require(''./lib/server''); // This is our custom server module.
const cluster = require(''cluster'');
const os = require(''os'');
// If we''re on the master thread start the forks.
if (cluster.isMaster) {
// Fork the process.
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork();
}
} else {
// If we''re not on the master thread start the server.
server.init();
}
Puede utilizar el módulo de clúster . Mira this
var cluster = require(''cluster'');
var http = require(''http'');
var numCPUs = require(''os'').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on(''exit'', function(worker, code, signal) {
console.log(''worker '' + worker.process.pid + '' died'');
});
} else {
// Workers can share any TCP connection
// In this case its a HTTP server
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world/n");
}).listen(8000);
}
Ryan Dahl responde a esta pregunta en la charla técnica que dio en Google el verano pasado. Parafraseando, "simplemente ejecute procesos de múltiples nodos y use algo sensato para permitirles comunicarse. Por ejemplo, sendmsg (), estilo IPC o RPC tradicional".
Si desea ensuciarse las manos de inmediato, consulte el módulo spark2 Forever .Hace que engendrar procesos de múltiples nodos sea trivialmente fácil. Se encarga de configurar el puerto compartido, de modo que cada uno puede aceptar conexiones al mismo puerto, y también reaparecer automáticamente si desea asegurarse de que un proceso se reinicia si / cuando muere.
ACTUALIZACIÓN - 10/11/11 : El consenso en la comunidad de nodos parece ser que Cluster es ahora el módulo preferido para administrar múltiples instancias de nodos por máquina. Forever vale la pena echar un vistazo.
Spark2 se basa en Spark que ya no se mantiene. Cluster es su sucesor, y tiene algunas características interesantes, como generar un proceso de trabajo por núcleo de CPU y respawning trabajadores muertos.
También es posible diseñar el servicio web como varios servidores independientes que escuchan sockets de Unix, de modo que puede empujar funciones como el procesamiento de datos en procesos separados.
Esto es similar a la mayoría de las arquitecturas de servidor web scrpting / database donde un proceso cgi maneja la lógica de negocios y luego empuja y extrae los datos a través de un socket Unix a una base de datos.
la diferencia es que el procesamiento de datos se escribe como un servidor web de nodo que escucha en un puerto.
es más complejo, pero en última instancia es donde debe ir el desarrollo de múltiples núcleos. una arquitectura multiproceso que utiliza múltiples componentes para cada solicitud web.
Un método sería ejecutar varias instancias de node.js en el servidor y luego colocar un equilibrador de carga (preferiblemente uno no bloqueante como nginx) delante de ellos.