node 服务实现平滑重启

  •  服务器 安装 forever 依赖

forever是一个用于在Node.js应用程序中运行脚本的工具,它可以确保脚本持续运行,即使脚本异常退出或崩溃也能自动重启。    

  • 开启 node 服务
# 开启服务
forever start app.js  # 需要把 app.js 替换成 项目入口文件

# 重启服务
forever restart app.js

# 停止服务
forever stop app.js

# 列出当前运行的所有脚本和它们的进程ID。
forever list

# 显示指定脚本的日志输出。
forever logs app.js
  • 但是 forever 重启时,依旧会 导致长连接的用户或会话状态 断开,怎么处理?
  1.  PM2 是一个 进程管理工具,可以创建一个新实例,让新用户都连接到新实例,并且旧实例 等用户断开之后再关闭
  2. 如果 你的项目 使用了多进程,是不是可以,先重启部分进程,等重启完成后,再重启其他进程呢?
  •  cluster 模块 开启 多个进程
  •  主进程 监听 SIGUSR2 信号
  •  主进程 给 工作进程 使用 IPC 通信,给 第一个 工作进程关闭 disconnect --> 创建新的 工作进程 完成之后 开始 第二个,等所有的 进程完成 即可实现平滑重启服务

优雅重启 的 核心 disconnect 函数:

  • 切断 主进程跟 工作进程之间的 IPC 通信
  • 主进程 将在不会 再分配 新的连接 给此工作进程
  • 注意 对于 keep-alive 连接,依旧会 保留 在这个 工作进程中( autocannon 压测就是 keep-alive 连接 )
  • 直到 所有接连处理完成 以及 keep-alive 关闭 后,此工作进程将会关闭,触发进程的 exit 生命周期
  •  如果 子进程 正在有用户连接,就会等待连接关闭后,重新尝试关闭
  •  主进程 监听到 子进程关闭后,开启一个新的 进程

  •   代码实现
require('dotenv').config();
const cluster = require('cluster');
const os = require('os');
const app = require('../app'); // 导入Express应用程序

if (cluster.isMaster) {
  console.log(`Master 服务开启  ${process.pid}`);

  // 获取系统的 CPU 核心数量
  const numCPUs = os.cpus().length;

  // 根据 CPU 核心数量创建工作进程
  for (let i = 0; i < numCPUs / 2; i++) {
    cluster.fork();
  }

  // 监听工作进程退出事件
  cluster.on('exit', (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 关闭   code ${code} signal ${signal}`);
  });

  // 监听SIGUSR2信号,优雅地重启工作进程
  process.on('SIGUSR2', () => {
    console.log('接收到 SIGUSR2 信号, 正在执行重启');
    const workers = Object.values(cluster.workers);

    const restartWorker = (workerIndex) => {
      if (workerIndex >= workers.length) return;
      const worker = workers[workerIndex];
      console.log(`停止工作进程 ${worker.process.pid}`);
      
      worker.disconnect();

      worker.on('exit', () => {
        if (!worker.exitedAfterDisconnect) return;
        const newWorker = cluster.fork();
        newWorker.on('listening', () => {
          console.log(`工作进程 ${newWorker.process.pid} 启动`);
          restartWorker(workerIndex + 1);
        });
      });
    };

    restartWorker(0);
  });

  // 监听SIGTERM信号,关闭所有的工作进程
  process.on('SIGTERM',()=>{
    Object.values(cluster.workers).forEach((worker) => {
      console.log(`工作进程 ${worker.process.pid} 接收到 停止 信号`);
      worker.disconnect();
    });
  })
  
} else {
  // 启动 Express 应用程序
  app.listen(process.env.NODE_SERVE, ()=>{ console.log(`worker 服务开启  ${process.pid}`) })
}
  • 平滑重启
# 平滑重启 多工作进程的 node 服务
kill -s SIGUSR2 <pid>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上的小蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值