【已经解决】Nodejs关于pm2与自己写的自动重启代码冲突问题(主要就是cluster)

【已经解决】Nodejs关于pm2与自己写的自动重启代码冲突问题(主要就是cluster)

###几句废话先: 以前没有用到过pm2也就是因为还没有到用到它的时候, 今天头一次使用让我产生很多困惑,于是乎,我来到这了。:) ###具体问题: 我在我的app.js文件夹里面写了关于自动重启的代码,也就是使用的cluster这个package, 代码就不贴了,两天的测试运行没有问题,同时网上也有关于cluster的相关解答。 我的也就是和官网差不多,唯一的区别就是使用的domain这个package。但当我使用pm2 start app.js 首次启动时,一切正常,简单的测试后也没问题,当我,stop后,我看了它的logs。

第一个疑惑:在我使用node app时,因为是4核的会显示几个worker的相关信息,然而我用pm2启动时 只有一个master的启动信息。

第二个困惑:我在使用pm2启动后,并且stop后,再用node app启动,发现启动不了, 报错也是:NOT RUNNING。之后我再用pm2启动,发现它会自动的重启,一会也就达到1k+了,之后,它就不会再自动重启了,status就直接是:errored,但是,我的程序本身没有问题,也就是换了两种启动方法。

第三个困惑:老是不好启动怎么办?两个都不好启动了,怎么办?我也就是没办法,结束进程!! 之后再用pm2重启,擦--成功了,一切正常。

###我的猜想: 因为考虑到结束进程之后就启动成功了,我想他所有的状态和bind的信息都保存在这个进程中,之所以在 这会提到bind,因为,我在用node app启动的时候,他也报错,说bind EADDRINUSE 这里的是不是指端口号?因为我端口号在两个不同的启动方式里都没变, 并且stackoverflow上也有次问题的相似者
###您的思考和想法是什么: loading------


3 回复

【已经解决】Nodejs关于pm2与自己写的自动重启代码冲突问题(主要就是cluster)

几句废话先:

以前没有用到过pm2,也就是因为还没有到用到它的时候。今天头一次使用让我产生很多困惑,于是乎,我来到这里。:)

具体问题:

我在我的app.js文件中写了关于自动重启的代码,也就是使用的cluster这个package。代码就不贴了,两天的测试运行没有问题,同时网上也有关于cluster的相关解答。我的也就是和官网差不多,唯一的区别就是使用的domain这个package。

但当我使用pm2 start app.js首次启动时,一切正常,简单的测试后也没问题。当我stop后,我看了它的logs。

第一个疑惑:

在我使用node app时,因为是4核的会显示几个worker的相关信息,然而我用pm2启动时只有一个master的启动信息。

第二个困惑:

我在使用pm2启动后,并且stop后,再用node app启动,发现启动不了,报错也是:NOT RUNNING。之后我再用pm2启动,发现它会自动的重启,一会儿也就达到1k+了,之后,它就不会再自动重启了,status就直接是:errored。但是,我的程序本身没有问题,也就是换了两种启动方法。

第三个困惑:

老是不好启动怎么办?两个都不好启动了,怎么办?我也就是没办法,结束进程!!之后再用pm2重启,擦--成功了,一切正常。

我的猜想:

因为考虑到结束进程之后就启动成功了,我想他所有的状态和bind的信息都保存在这个进程中。之所以在这里提到bind,是因为我在用node app启动的时候,他也报错,说bind EADDRINUSE。这里的是不是指端口号?因为我端口号在两个不同的启动方式里都没变,并且StackOverflow上也有这个问题的相似者。

您的思考和想法是什么:

首先,pm2是一个进程管理器,它可以帮助我们更好地管理和监控Node.js应用。当我们使用pm2启动应用时,它会自动处理一些事情,比如自动重启、负载均衡等。而我们手动编写的cluster模块也可以实现类似的功能,这就导致了冲突。

解决方案:

1. 使用pm2自带的负载均衡功能

// app.js
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', (worker, code, signal) => {
        console.log(`Worker ${worker.process.pid} died`);
        cluster.fork(); // 自动重启
    });
} else {
    // Workers can share any TCP connection
    // In this case it is an HTTP server
    http.createServer((req, res) => {
        res.writeHead(200);
        res.end('hello world\n');
    }).listen(8000);
}

2. 停止使用自定义的cluster模块

如果想要使用pm2的负载均衡功能,可以停止使用自定义的cluster模块。pm2已经内置了这个功能。

3. 端口冲突问题

确保你的应用在启动时不会尝试绑定已经被占用的端口。可以在配置文件中指定不同的端口号或者动态获取可用的端口号。

const port = process.env.PORT || 8000;
http.createServer(...).listen(port);

通过以上步骤,你应该能够解决pm2与自定义的cluster模块之间的冲突问题。


自己已经解决,但我想听听各位的想法 :)

回答

首先,pm2 是一个强大的生产进程管理工具,它本身就支持自动重启、负载均衡等功能。而你在代码中使用 cluster 模块来实现类似的自动重启功能,这确实可能导致冲突。

第一个疑惑

当你使用 pm2 启动应用时,默认情况下,pm2 会管理多个工作进程(worker),而不是像 cluster 那样手动管理。因此,你看到的只有 master 进程的启动信息,是因为 pm2 自动处理了 worker 的创建和管理。

第二个困惑

当你使用 node app.js 启动应用时,如果你手动实现了 cluster 的功能,那么这些进程可能没有被正确地管理和监控。当你使用 pm2 启动应用后,再次尝试用 node app.js 启动时,可能会遇到端口已经被占用的问题(即 EADDRINUSE 错误)。这是因为 pm2 在关闭应用时,可能并没有完全释放所有资源,导致端口仍然被占用。

解决方案

1. 停止使用自定义的 cluster 实现

你可以完全依赖 pm2 来处理多进程和自动重启逻辑。只需要配置 pm2 文件(如 ecosystem.config.js)即可。

module.exports = {
  apps: [
    {
      name: "my-app",
      script: "./app.js",
      instances: "max", // 使用最大核心数
      autorestart: true,
      watch: true, // 监视文件变化
      max_memory_restart: "1G", // 当内存超过1G时自动重启
    },
  ],
};

然后使用 pm2 start ecosystem.config.js 启动你的应用。

2. 清理端口占用

如果你需要手动管理端口,可以在启动前确保端口是可用的:

const net = require('net');

const PORT = 3000;
const server = net.createServer();

server.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(`Port ${PORT} is already in use`);
  } else {
    throw err;
  }
});

这样可以确保在启动应用之前,端口是可用的。

希望这些解决方案能够帮助你解决问题。

回到顶部