module.exports = {
apps: [
{
name: "my-api",
script: "./dist/index.js",
instances: "max",
exec_mode: "cluster",
env: {
NODE_ENV: "production",
PORT: 3000
},
max_memory_restart: "600M",
kill_timeout: 4000,
wait_ready: true,
listen_timeout: 8000,
autorestart: true,
watch: false
}
]
};Să fim sinceri: mulți începem cu pm2 start app.js și sperăm să fie bine. Am făcut și eu asta acum vreo 6 ani la un proiect cu vreo 15.000 de useri activi, până când s-a umplut SSD-ul de la loguri nesegmentate și serverul a crăpat fiindcă Node a mâncat toată memoria. Atunci mi-am dat seama că fără un ecosystem.config.js bine pus la punct, te joci cu focul în producție.
Astăzi vreau să vă arăt configurația pe care o folosesc ca template pe aproape orice VPS. Rezolvă din start trei mari probleme: downtime-ul la deploy, memory leak-urile și logurile gigantice.
Cluster Mode și Graceful Reload fără downtime
Node.js rulează single-threaded. Dacă ai un server cu 4 nuclee CPU și pornești aplicația standard, folosești doar 25% din puterea mașinii. Setând instances: "max" și exec_mode: "cluster", PM2 va porni câte o instanță pentru fiecare core și va face load balancing între ele.
Dar atenție la marele trade-off: aplicația ta trebuie să fie complet stateless. Dacă salvezi sesiuni în memoria RAM (in-memory sessions) sau folosești socket-uri fără un adaptor precum Redis, cluster mode o să-ți dea peste cap logica. Userul va nimeri ba pe instanța 1, ba pe instanța 2 și va fi deconectat aleatoriu.
Partea cea mai mișto la cluster mode este că poți face pm2 reload ecosystem.config.js. Spre deosebire de restart (care oprește tot și pornește iar, lăsând userii în aer câteva secunde), reload repornește instanțele pe rând. Zero downtime garantat. Ca să funcționeze corect, în codul tău de Express sau Fastify trebuie să asculți semnalul SIGINT și să închizi conexiunile la baza de date înainte ca procesul să fie omorât:
process.on('SIGINT', () => {
server.close(() => {
// închide conexiuni DB, Redis etc.
process.exit(0);
});
});
Limita de memorie (OOM) și logurile care umplu discul
Node are prostul obicei să se lăcomească la memorie dacă are de procesat volume mari de date sau dacă ai un memory leak mic pe undeva. Prin max_memory_restart: "600M", îi spui lui PM2 să dea un restart curat instanței dacă depășește acest prag. Pentru majoritatea aplicațiilor de Express, 500-600MB sunt suficienți per instanță.
Apoi, avem problema logurilor. PM2 scrie tot ce dai prin console.log în niște fișiere text brute. Dacă nu le controlezi, în câteva luni te trezești cu fișiere de 10GB și un sistem de operare blocat.
Soluția mea preferată nu e în fișierul de config, ci în modulul pm2-logrotate. Îl instalezi o singură dată pe server cu pm2 install pm2-logrotate și el se ocupă să împartă logurile zilnic sau când ating 10MB, păstrând doar ultimele 30 de arhive.
Un config de producție gata de drum
Mai jos aveți fișierul de configurare pe care îl folosesc cel mai des. Este curat, are variabile de mediu setate clar și folosește tot ce am discutat mai sus.
Voi cum gestionați procesele Node în producție? Mergeți pe PM2 clasic sau ați trecut complet pe Docker și Kubernetes chiar și pentru proiecte medii?