Nodejs如何无伤更新?

Nodejs如何无伤更新?

nodejs有个问题一直困扰着我,nodejs如何做到无伤更新?也就是说如果有一个版本需要更新,那么是需要重启的,对于web来说还好,但是对于游戏来说就麻烦了,要维护着长连接,如果重启,肯定是不行的,求个解决方案?

8 回复

当然可以。无伤更新(也称为热更新或零停机更新)在Node.js中是一个常见的需求,尤其是在处理实时应用(如游戏)时。为了实现这一点,我们可以使用一些技术和策略来确保在更新过程中服务不会中断。

解决方案概述

  1. 进程管理工具:使用像PM2这样的进程管理工具可以帮助我们轻松地进行无伤更新。
  2. 集群模式:利用Node.js的内置集群模块,可以在不中断服务的情况下逐步替换旧实例。
  3. 代码热加载:使用一些框架或库(如nodemon)来自动检测代码变化并重新加载。

示例代码

使用PM2进行无伤更新

首先,你需要安装PM2:

npm install pm2 -g

然后,在你的项目目录中创建一个ecosystem.config.js文件,用于配置PM2:

module.exports = {
  apps: [
    {
      name: 'my-app',
      script: './index.js',
      instances: 'max',
      autorestart: true,
      watch: true,
      ignore_watch: ["node_modules"],
      max_memory_restart: '1G',
      env: {
        NODE_ENV: "development"
      },
      env_production: {
        NODE_ENV: "production"
      }
    }
  ]
};

启动应用:

pm2 start ecosystem.config.js --env production

更新应用时,可以使用以下命令:

pm2 reload my-app

使用集群模式

你可以使用Node.js的内置cluster模块来实现无伤更新:

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

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // 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);

  console.log(`Worker ${process.pid} started`);
}

当你需要更新代码时,可以先停止当前的Worker,然后启动新的Worker。由于集群模式会自动分配请求到其他可用的Worker,所以不会中断服务。

总结

通过使用PM2或Node.js的集群模式,你可以实现无伤更新。这些方法允许你在不中断服务的情况下替换旧的进程或Worker。根据你的具体需求选择合适的方法,并确保在生产环境中进行充分测试。


  1. 做个代理, 并对请求设置对应的权重,如:proxy = s1(60%) + s2(40%);
  2. 有更新时,降低 s2 的权重(降低为0则关闭连接请求)。新的请求会到 s1 上
  3. s2 上已有的连接你不想丢失,只能等待所有连接正常断开
  4. 当 s2 上无活动连接时,可以进行更新
  5. 更新完成后,恢复对应的权重

小修正依赖短时的断线重连(游戏不可能不做断线重连吧). 大更新追求一致性, 不可能不停机维护.

大版本肯定是停机维护的,但是偶尔要修个什么BUG啊,或者上个什么小功能之类的,也要重启,感觉很不靠谱啊,一瞬间全断了,然后一瞬间全重连!并发瞬间高起来了。。

这样当然是可以,有没有什么软件可以在前面承载连接,然后把具体的逻辑处理交由另一个服务来完成,如果有这样的软件就好了。这样逻辑的更新完全不影响。

自己游戏内部可以实现热发布的吧……

热代码替换 socket保持 然后不同的请求调用的不同的require进来的模块 模块文件改变的时候把require的cache删除重新require就可以做到了 我们游戏现在就是这样了

为了实现Node.js应用的无伤更新(也称为热更新或零停机更新),我们可以采用几种不同的方法。一个常见的方法是使用PM2进程管理器,并结合其内置的滚动重启功能。这种方法可以在不中断现有连接的情况下逐步更新应用。

以下是具体的步骤和示例代码:

  1. 安装PM2: 如果还没有安装PM2,可以通过npm全局安装:

    npm install -g pm2
    
  2. 配置PM2启动文件: 创建一个ecosystem.config.js文件,用于定义应用的启动参数:

    module.exports = {
      apps: [
        {
          name: 'my-app',
          script: './app.js',
          instances: 1,
          autorestart: true,
          watch: false,
          max_memory_restart: '1G',
          env: {
            NODE_ENV: 'development',
          },
          env_production: {
            NODE_ENV: 'production',
          }
        }
      ]
    };
    
  3. 使用PM2进行滚动更新: 当需要更新应用时,可以使用以下命令:

    pm2 reload my-app --update-env
    

    这条命令会先启动一个新的进程,然后逐个关闭旧的进程。在这个过程中,现有的客户端连接不会被中断。

  4. 确保长连接兼容性: 对于涉及长连接的应用(如游戏),需要确保在更新过程中不会断开现有连接。可以通过保持连接活跃和重新连接机制来处理。例如,可以定期发送心跳包以维持WebSocket连接。

  5. 代码示例: 假设你有一个简单的WebSocket服务器:

    const WebSocket = require('ws');
    
    const wss = new WebSocket.Server({ port: 8080 });
    
    wss.on('connection', function connection(ws) {
      ws.on('message', function incoming(message) {
        console.log('received: %s', message);
      });
    
      // 心跳包逻辑
      setInterval(() => ws.send('ping'), 30000); // 每30秒发送一次心跳
    });
    

通过上述步骤,你可以实现Node.js应用的无伤更新,即使是在长连接应用中也能保持服务的连续性和稳定性。

回到顶部