- 服务器 安装 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 重启时,依旧会 导致长连接的用户或会话状态 断开,怎么处理?
- PM2 是一个 进程管理工具,可以创建一个新实例,让新用户都连接到新实例,并且旧实例 等用户断开之后再关闭
- 如果 你的项目 使用了多进程,是不是可以,先重启部分进程,等重启完成后,再重启其他进程呢?
- 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>