Hace solo un par de horas, comencé un debate sobre el hecho de que Node.JS es demasiado lento para grandes proyectos y debería preferir Golang, Rust, PHP, etc. El argumento principal del lado opuesto en esta disputa fue el hecho de que JavaScript es de un solo subproceso. Supuestamente, cuando se desarrolla una aplicación, la productividad simplemente descansa en contra de este subproceso único y ya no se puede hacer nada, solo reescríbalo en otro idioma. Sin embargo, las cosas están un poco mejor con NodeJS de lo que parece a primera vista. Antes de profundizar en este tema, quiero declarar que respeto el derecho de cada desarrollador a usar el lenguaje de programación que le gustó y que considera preferible en una tarea en particular.
Después de buscar la palabra clave "PM2" en Habr, no encontré ningún artículo dedicado a este administrador de procesos. Solo referencias únicas en artículos de otros usuarios. Me emocioné (conté contundentemente) con la idea de ponerme al día y arrojar luz sobre este rincón oscuro del desarrollo del backend en Node.JS (que muchas personas saben, sí, lo sé). Le pregunto a todos los interesados bajo cat.
Algunas palabras sobre el propio PM2
PM2 es un administrador de procesos de código abierto con licencia bajo la licencia AGPL-3.0. Al momento de escribir, tiene ~ 350k descargas semanales, según NPM. Se utiliza principalmente en entornos en los que necesita ejecutar una aplicación en NodeJS y olvidarse de ella (también puede usarla con otros idiomas, pero más adelante), lo que le permite agrupar la aplicación y distribuir de manera flexible la carga entre los núcleos del procesador. Un pequeño recorte del
repositorio PM2 en GitHub :
PM2 es un administrador de procesos de producción para aplicaciones Node.js con un equilibrador de carga incorporado. Le permite mantener las aplicaciones vivas para siempre, volver a cargarlas sin tiempo de inactividad y facilitar las tareas comunes de administración del sistema.
Cuando se desarrollan, muchos recién llegados encuentran un problema cuando, después de "implementar" la aplicación en el servidor de producción, no saben cómo lanzarla "para siempre". Escriben
set NODE_ENV=production && node app.js
en la consola SSH, todo está bien, la aplicación funciona. Cierre la consola y la aplicación ya no funcionará. Pregunta de StackOverflow:
¿cómo ejecutar la aplicación node.js de forma permanente? anotó más de 237 mil visitas de todos los tiempos.
PM2 resuelve este problema con un comando:
pm2 start app.js
Este comando "demoniza" (del inglés "daemonize") el proceso NodeJS, monitorea su consumo de memoria y considera la carga del procesador.
De vuelta a nuestros carneros
Con la creciente carga en el backend, se hace necesario escalarla, tanto vertical como horizontalmente, para quien sea más conveniente en las circunstancias. Como sabemos, un proceso puede usar varios núcleos de procesador, pero solo si hay varios hilos dentro del proceso. En aplicaciones NodeJS, el flujo es uno. PM2 puede ayudar en esta situación y distribuir la carga entre varios núcleos de procesador. Aún con un solo comando:
pm2 start app.js -i max
En este caso, el parámetro
max corresponde al número de núcleos de procesador. Es decir Se crearán 8 procesos separados para el procesador de 8 núcleos. También puede establecer
-1 en lugar de
max, y luego el número de procesos corresponderá al
número de núcleos
menos 1 . Todo el encanto es que las conexiones HTTP (S) / Websocket / TCP / UDP se distribuirán uniformemente entre estos procesos. ¿Por qué no escala horizontal? Puede leer más acerca de la agrupación en clúster en PM2 aquí:
modo de clúster PM2 .

Puede ejecutar tantos procesos como desee, pero aún así se recomienda cumplir con la recomendación "un proceso por núcleo".
Respeto por la memoria
Al desarrollar en PHP, una vez me encontré con un problema. Debido a la inexperiencia, inconscientemente colocó un error en el motor del sistema, debido a que, bajo ciertas condiciones, los procesos comenzaron a comer demasiada RAM. Además de esto, se cargó el procesador, por lo que la máquina virtual simplemente colgó y no tuve acceso a ella en absoluto.
Como saben los desarrolladores de PHP, en PHP-FPM puede especificar el tipo de distribución de procesos (si de repente no lo sabía, entonces en PHP-FPM se crea un nuevo proceso para cada nueva solicitud) - estático, cuando se establecen los umbrales mínimo y máximo, y dinámico - asignación de cuánto tantos procesos grandes como sea necesario. ¿Qué sucederá en PM2 si inicia 8 procesos y todos comienzan a consumir mucha memoria? Y PM2 puede resolver este problema, con solo un parámetro en la línea de comando:
# Set memory threshold for app reload pm2 start app.js -i max --max-memory-restart <200MB>
Cada vez que se alcanza el límite de memoria, PM2 reiniciará automáticamente el proceso. Distribuir memoria es más fácil que los procesos, ¿no es así? 8 procesos * 200 megabytes = 1.6 gigabytes. Matemáticas de segunda clase.
Además de reiniciar el proceso, también puede configurar el reinicio después de un intervalo de tiempo N. Todavía no he descubierto en qué casos esto puede ser útil, pero no dude en señalarme un par de ejemplos en los comentarios :)
¿Y si reinicio la máquina virtual?
Sorpresa-sorpresa! PM2 también resuelve este problema por ti. Aún con no más de un solo comando en la consola:
pm2 startup
PM2 generará un script que generará todos los procesos necesarios cuando se inicie el sistema operativo. Sin embargo, debe estar atento: al actualizar la versión de Node.JS, todo puede romperse. Para evitar esto, después de actualizar con éxito a la nueva versión de Node.JS, ejecute
pm2 unstartup
y
pm2 startup
. Puede leer más sobre esto en el enlace -
PM2 Startup Script Generator .
¿Es necesario reiniciar los clústeres manualmente al hacer cambios?
Por supuesto que no! Bueno, más precisamente, usted, por supuesto, puede reiniciar la aplicación manualmente, pero ¿por qué? ¡Automatiza todo lo que puedas y que la fuerza te acompañe!
pm2 start env.js --watch --ignore-watch="node_modules"
Puede usar esto cuando combine una rama maestra en un repositorio local con una rama maestra de un repositorio remoto. En mi proyecto paralelo, esto se hace simplemente:
git pull origin master && npm run build
. Al cambiar los archivos en las carpetas
servidor / compilación y
cliente / compilación , los procesos se reiniciarán automáticamente. Entiendo que esta es una característica muy simple y ni siquiera merece ser mencionada en este texto. Lo diluiré con algo serio y escribiré que si usas clustering, todos los procesos se reiniciarán por turnos. Sí, para que al menos uno de ellos siempre esté disponible. ¡Esta es una implementación de tiempo de inactividad cero!
Y no puede reiniciar los procesos. Hay una recarga para esto (algo similar a la recarga de nginx):
pm2 reload all
¡Demasiados equipos! En general, prefiero las configuraciones
Ya estoy aburrido de crear frases divertidas, así que es simple y banal: hay un archivo de ecosistema. Los formatos admitidos son JSON, YAML y JS. Por ejemplo, cuando necesita monitorear archivos en las carpetas del
servidor y del
cliente :
module.exports = { apps: [{ script: "app.js", watch: ["server", "client"], env_production : { "NODE_ENV": "production" } }] }
Para obtener más información, consulte el enlace:
Declaración de aplicación PM2 .
¡Y hasta el monitoreo lo es!
Y no uno. Elige el que más te guste. Puede monitorear en la consola con el comando:
pm2 monit

O use la versión completa de monitoreo basado en la web:

Usted, por supuesto, no me creerá, pero se instala y se inicia con
un comando:
pm2 plus
Y mucho, mucho más ...
Soporte declarado para Heroku y Docker, incremento automático de puertos con la capacidad de transferir a
process.env
(cuando necesita ejecutar cada proceso en un puerto separado), el lanzamiento de varias instancias PM2 dentro del mismo sistema operativo, la presencia de una API de software y la capacidad de ejecutar scripts demonizados de Bash y Python.
Probablemente me perdí algo más importante o interesante, que siempre puedes recordarme en los comentarios. Espero que hayas podido aprender algo nuevo de este artículo.