tutorial side node framework caracteristicas javascript node.js serverside-javascript web-worker

javascript - side - Node.js y solicitudes intensivas de CPU



node js tutorial (5)

Comencé a jugar con el servidor HTTP Node.js y realmente me gusta escribir Javascript del lado del servidor, pero algo me impide comenzar a usar Node.js para mi aplicación web.

Comprendo todo el concepto de E / S asíncrono, pero me preocupa un poco el caso de los casos extremos en los que el código de procedimiento requiere mucha CPU, como la manipulación de imágenes o la clasificación de grandes conjuntos de datos.

Como lo entiendo, el servidor será muy rápido para solicitudes de páginas web simples, como ver una lista de usuarios o ver una publicación de blog. Sin embargo, si quiero escribir un código muy intensivo de CPU (por ejemplo, en el back-end del administrador) que genere gráficos o cambie el tamaño de miles de imágenes, la solicitud será muy lenta (unos pocos segundos). Dado que este código no es asíncrono, todas las solicitudes que lleguen al servidor durante esos pocos segundos se bloquearán hasta que se realice mi solicitud lenta.

Una sugerencia fue utilizar trabajadores web para tareas intensivas de CPU. Sin embargo, me temo que los trabajadores web harán que sea difícil escribir código limpio, ya que funciona al incluir un archivo JS separado. ¿Qué sucede si el código de uso intensivo de la CPU se encuentra en el método de un objeto? Es un poco difícil escribir un archivo JS para cada método que requiere una gran cantidad de CPU.

Otra sugerencia fue generar un proceso secundario, pero eso hace que el código sea aún menos fácil de mantener.

¿Alguna sugerencia para superar este obstáculo (percibido)? ¿Cómo se escribe código limpio orientado a objetos con Node.js y se asegura de que las tareas pesadas de la CPU se ejecuten de forma asíncrona?


Lo que necesitas es una cola de tareas! Mover sus tareas de larga duración fuera del servidor web es una BUENA cosa. Mantener cada tarea en un archivo js "separado" promueve la modularidad y la reutilización del código. Te obliga a pensar en cómo estructurar tu programa de una manera que facilite la depuración y el mantenimiento a largo plazo. Otro beneficio de una cola de tareas es que los trabajadores pueden escribirse en un idioma diferente. Simplemente haga una tarea, haga el trabajo y vuelva a escribir la respuesta.

algo como esto https://github.com/resque/resque

Aquí hay un artículo de github acerca de por qué lo construyeron http://github.com/blog/542-introducing-resque


No desea que su código de CPU intensivo se ejecute de forma asíncrona, sino que se ejecute en paralelo . Debe obtener el trabajo de procesamiento del subproceso que atiende las solicitudes HTTP. Es la única manera de resolver este problema. Con NodeJS, la respuesta es el módulo de agrupación , para generar procesos secundarios para hacer el trabajo pesado. (El nodo AFAIK no tiene ningún concepto de subprocesos / memoria compartida; es procesos o nada). Tienes dos opciones para estructurar tu aplicación. Puede obtener la solución 80/20 generando 8 servidores HTTP y manejando las tareas intensivas en cómputo de forma síncrona en los procesos secundarios. Hacer eso es bastante simple. Podrías tomarte una hora para leer sobre eso en ese enlace. De hecho, si simplemente arrancas el código de ejemplo en la parte superior de ese enlace, obtendrás el 95% del camino.

La otra forma de estructurar esto es configurar una cola de trabajos y enviar grandes tareas de cálculo a través de la cola. Tenga en cuenta que hay una gran sobrecarga asociada con el IPC para una cola de trabajos, por lo que esto solo es útil cuando las tareas son considerablemente más grandes que la sobrecarga.

Me sorprende que ninguna de estas otras respuestas mencione el cluster.

Antecedentes: el código asíncrono es un código que se suspende hasta que algo sucede en otro lugar , momento en el que el código se activa y continúa su ejecución. Un caso muy común donde algo lento debe suceder en otro lugar es I / O.

El código asíncrono no es útil si es su procesador el responsable de hacer el trabajo. Ese es precisamente el caso de las tareas de "computación intensiva".

Ahora, podría parecer que el código asíncrono es un nicho, pero en realidad es muy común. Simplemente sucede que no es útil para las tareas intensivas de cómputo.

Esperar en E / S es un patrón que siempre ocurre en servidores web, por ejemplo. Cada cliente que se conecta a su servidor recibe un socket. La mayoría de las veces las tomas están vacías. No desea hacer nada hasta que un socket reciba algunos datos, en cuyo momento desea manejar la solicitud. Bajo el capó, un servidor HTTP como Node está utilizando una biblioteca de eventos (libev) para realizar un seguimiento de los miles de sockets abiertos. El sistema operativo notifica a libev, y luego libev notifica a NodeJS cuando uno de los sockets obtiene datos, y luego NodeJS coloca un evento en la cola de eventos, y su código http se activa en este punto y maneja los eventos uno tras otro. Los eventos no se ponen en cola hasta que el socket tiene algunos datos, por lo que los eventos nunca esperan datos, ya están ahí para ellos.

Los servidores web basados ​​en eventos de un solo subproceso tienen sentido como paradigma cuando el cuello de botella está esperando en un grupo de conexiones de socket mayormente vacías y no desea un subproceso o proceso completo para cada conexión inactiva y no desea encuestar sus 250k sockets para encontrar el siguiente que tiene datos en él.


Un par de enfoques que puede utilizar.

Como notas de @Tim, puede crear una tarea asíncrona que se encuentre fuera o paralela a su lógica de servicio principal. Depende de sus requisitos exactos, pero incluso cron puede actuar como un mecanismo de puesta en cola.

Los Trabajadores Web pueden trabajar para sus procesos asíncronos, pero actualmente no son compatibles con node.js. Hay un par de extensiones que proporcionan soporte, por ejemplo: http://github.com/cramforce/node-worker

Aún puede reutilizar módulos y código a través del mecanismo estándar de "requisitos". Solo debe asegurarse de que el envío inicial al trabajador pase toda la información necesaria para procesar los resultados.


Esto es un malentendido de la definición de servidor web, solo debe usarse para "hablar" con los clientes. Las tareas de carga pesada deben delegarse a programas independientes (que, por supuesto, también se pueden escribir en JS).
Probablemente diría que está sucio, pero le aseguro que un proceso de servidor web atascado en el cambio de tamaño de las imágenes es simplemente peor (incluso para, digamos, Apache, cuando no bloquea otras consultas). Aún así, puede usar una biblioteca común para evitar la redundancia de código.

EDIT: he venido con una analogía; La aplicación web debe ser como un restaurante. Tienes meseros (servidor web) y cocineros (trabajadores). Los camareros están en contacto con los clientes y realizan tareas sencillas como proporcionar un menú o explicar si algún plato es vegetariano. Por otro lado delegan tareas más duras a la cocina. Debido a que los meseros solo hacen cosas simples, responden rápido y los cocineros pueden concentrarse en su trabajo.

Node.js aquí sería un camarero único pero con mucho talento que puede procesar muchas solicitudes a la vez, y Apache sería una pandilla de camareros tontos que solo procesan una solicitud para cada uno. Si este mesero de Node.js comenzara a cocinar, sería una catástrofe inmediata. Sin embargo, cocinar también puede agotar incluso a una gran cantidad de camareros apaches, sin mencionar el caos en la cocina y la disminución progresiva de la capacidad de respuesta.


Usar child_process es una solución. Pero cada proceso hijo generado puede consumir mucha memoria en comparación con Go goroutines

También puede utilizar una solución basada en cola, como kue