Node.js +Cluster

macCluster

Durante las últimas semanas, he estado jugando con Node.js, MongoDB y Redis. Con el fin de seguir mejorando mis capacidades en BackEnd, en los últimos días también he estado trasteando con el módulo Cluster de Node.js.  Este módulo realmente mejora la cantidad de carga que Express pueden manejar. Los resultados han sido asombrosos.

El módulo Cluster es bastante fácil de utilizar si estás acostumbrado a trabajar con el Node, pero me gustaría compartir mi experiencia a través de un sencillo tutorial esperando que pueda ser de ayuda a la comunidad.

Vale… pero… ¿Qué hace un Cluster?

Node.js corre en un solo hilo. Aunque es muy rápido en la mayoría de los casos, es inútil no utilizar el resto de procesadores si estos  están disponibles. El módulo Cluster permite crear una pequeña red de procesos separados que pueden compartir los puertos del servidor, con lo que podemos aprovechar toda la potencia de nuestro servidor. Dicho de otra forma, es muy útil para aprovechar las ventajas de los sistemas multi-core, ya que podremos poner en marcha un conjunto de procesos de Node para manejar la carga.

¿Cómo funciona?

Uno de los secretos a voces de node.js es que adopta muchos principios de Unix, llevándolos a su propio terreno. En este caso la creación de procesos es muy similar al modelo de Unix: un sencillo fork() crea una copia del proceso actual. A partir de ese momento el primer proceso se convierte en maestro o master, y la copia en un trabajador o worker. Es similar a cómo funcionan nginx o Apache, y a otros programas multi-proceso Linux.

Untitled drawing

Veamos un sencillo ejemplo

Para empezar vamos a construir el ejemplo de aplicación más sencillo posible con Node.js y Express. A continuación, añadiremos el Cluster. Por tanto, para empezar, es necesario que tengas Node.js instalado. Este tutorial es muy sencillo, y doy por hecho que tienes conocimientos de Javascript, Node.js y Express. Puedes ver una de nuestras anteriores entradas para ponerte al día.

Comenzamos

En primer lugar creamos una carpeta (yo la he llamado node-cluster) y añadimos nuestro fichero Package.json con el siguiente contenido:

Una vez hecho esto, es nuestro terminal y dentro de la ruta de la carpeta que hemos creado, ejecutamos el comando para instalar todo:

Ahora, crearemos nuestro fichero server.js. Será una aplicación básica utilizando Express.

Podemos ver que funciona correctamente de la siguiente manera:

  • ejecutamos en nuestro terminal el comando node server.js
  • accedemos a nuestro navegador a la ruta http://localhost:3000/ y veremos que nos devuelve “Hello SpeakinBytes!”

Perfecto! Ahora vamos al lío. Lo que haremos será modificar el fichero server.js para que utilice el módulo Cluster.

1.- Modificamos todo el fichero para que quede de la siguiente manera:

Como vemos, lo primero que hacemos es utilzar el require(‘cluster’).  A continuación estamos detectando si se trata del proceso master (el que empieza desde la línea de comandos al arrancar el servidor) o un worker (proceso creado por el master).  Si es un worker, hará exactamente lo mismo que hacía antes nuestra aplicación.

Ya sólo nos queda escribir el código del master:

Lo que hacemos es contar el número de CPU, y llamar a cluster.fork para cada uno de ellos. Si nuestro ordenador tiene 4 CPUs, tendremos cuatro workers ya que se llama a cluster.fork cuatro veces.

Si ejecutamos ahora el comando node server.js y lanzamos nuestro servidor, veremos en nuestra consola el mensaje Application running! varias veces. En mi caso son ocho, puesto que mi ordenador tiene ocho CPUs.

Para ver que todo está funcionando correctamente, vamos a modificar algunas líneas del proceso worker.

Ahora, cuando ejecutemos la aplicación arrancando el servidor, veremos en la consola los workers que se han lanzado. Además, cuando visitemos http://localhost:3000/ veremos el mensaje “Hello from Worker X”, donde X es el ID del worker que ha atendido la petición. Si abrimos varias pestañas del navegador o varios navegadores, veremos que obtenemos diferentes respuestas. Os dejo unos pantallazos de mi consola y de mis navegadores.

worker_consola2

worker2

Pero esto no es todo…

Vamos a añadir más cositas. Hay otra cosa que muy útil que podemos añadir a nuestro master. En el caso de  de que uno de nuestros procesos de trabajo muera (esperemos que no), vamos a querer asegurarse de lanzar otro, de lo contrario, en el peor de los casos, podríamos simplemente estar ejecutando un proceso master vacío y perderíamos todas nuestras peticiones!

Esto también es increíblemente fácil de hacer. Sólo hay que añadir el evento exit a nuestro Cluster, de manera que ya no tengamos que preocuparnos tanto si algo va muy mal en uno de nuestros workers.

Las dos últimas cosas que vamos a añadir son:

  • ver el evento listening. De esta manera sabremos que uno de nuestros workers está con el evento listening activo en nuestro servidor
  • Añadir un contador de solicitudes. Cada segundo mostraremos por consola el número de solicitudes que se han realizado. Para ello será necesario un paso de mensajes desde el worker al master, cosa que haremos con el comando process.send() en nuestro worker

Si ahora lanzamos nuestro servidor con el comando node server.js veremos en nuestra consola el resultado. Al hacer peticiones al navegador, también veremos en nuestra consola el número de solicitudes que se han contestado:

worker_consola1

worker_consola3

Y esto ha sido todo!!

Os dejo el link del código en Github así como todo el código a continuación. Espero que haya sido útil!

 

2 Responses to “Node.js +Cluster”

  1. Genial post, muchas gracias por la info.

Deja un comentario