Back to blog

PM2 Node.js 进程管理方案

PM2 的安装、进程管理、集群模式、日志轮转、零停机重载与开机自启,附 ecosystem 配置模板。

安装与基础使用

#

Node.js 进程上生产后需要守护:崩溃自动重启、日志轮转、多核利用、零停机更新。PM2 一条命令覆盖这些,另带监控面板和开机自启。

# 全局安装
npm install -g pm2

# 验证版本
pm2 --version

# 启动一个 Node.js 应用
pm2 start app.js
pm2 start app.js --name my-api          # 指定进程名称
pm2 start app.js -i max                 # 以集群模式启动,使用所有 CPU 核心
pm2 start app.js -- --port=3001         # 向应用传递参数

常用命令速查

#
# 进程管理
pm2 list              # 查看所有进程状态
pm2 show my-api       # 查看单个进程的详细信息
pm2 logs              # 实时查看所有日志
pm2 logs my-api       # 查看指定进程日志
pm2 monit            # 终端监控面板(CPU / 内存实时曲线)

# 生命周期
pm2 restart my-api    # 重启
pm2 reload my-api     # 零停机重载(集群模式)
pm2 stop my-api       # 停止
pm2 delete my-api     # 从 PM2 列表中移除

# 批量操作
pm2 restart all       # 重启所有进程
pm2 stop all          # 停止所有进程
pm2 delete all        # 清空所有进程

零停机重载 vs 重启

操作行为适用场景
restart杀死进程 → 启动新进程(有短暂停机)单实例、开发环境
reload逐个 worker 重启,始终保持至少一个在线生产环境集群模式
gracefulReload等待现有请求处理完毕再重启长连接、WebSocket

日志管理

# 查看日志
pm2 logs --lines 200                     # 显示最近 200 行
pm2 logs my-api --err                    # 只看错误日志
pm2 flush                                # 清空所有日志

# 日志轮转(内置模块)
pm2 install pm2-logrotate

# 配置轮转参数
pm2 set pm2-logrotate:max_size 50M       # 单文件上限
pm2 set pm2-logrotate:retain 7           # 保留最近 7 个归档
pm2 set pm2-logrotate:compress true      # 归档后 gzip 压缩

Ecosystem 配置文件

#

正式项目用 ecosystem.config.js 替代命令行参数,提交到版本库。

module.exports = {
  apps: [{
    name: 'api-server',
    script: 'dist/main.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
    env_development: {
      NODE_ENV: 'development',
      PORT: 3001,
      watch: ['src'],
      watch_delay: 1000,
      ignore_watch: ['node_modules', 'dist', 'logs'],
    },
    // 错误处理
    max_restarts: 10,
    restart_delay: 5000,
    min_uptime: '30s',
    // 日志
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    merge_logs: true,
    // 优雅退出
    kill_timeout: 5000,
    listen_timeout: 3000,
    // 健康检查
    max_memory_restart: '500M',
  }],
}

启动时选择环境:

pm2 start ecosystem.config.js                  # 默认使用 env
pm2 start ecosystem.config.js --env development # 使用 env_development

集群模式

#

Node.js 单线程,一台机器有多少核就起多少 worker 才用得满。

instances: 'max',      // 自动检测 CPU 核心数
instances: 4,           // 手动指定数量
instances: 0,           // 与 max 相同

reload 的执行流程:

worker 1 ########....   <- 正在服务的连接
worker 2 ########....
worker 3 ########....
worker 4 ########....

pm2 reload api-server

worker 1 ########....  <- 正在关闭
worker 2 ............  <- 已启动新版
worker 3 ########....  <- 正在关闭
worker 4 ............  <- 已启动新版

逐个替换 worker,全程至少有一个在响应请求。

开机自启

#
# 生成系统自启脚本
pm2 startup

# 保存当前进程列表(重启后自动恢复)
pm2 save

# 查看已保存的进程
pm2 resurrect

pm2 startup 自动检测初始化系统(systemd / launchd / rc.d)并生成对应脚本。

部署:搭配 Git 的远程部署

#

PM2 内置 deploy,从 Git 拉代码并自动重启。

module.exports = {
  apps: [{
    name: 'api',
    script: 'dist/main.js',
  }],
  deploy: {
    production: {
      user: 'deploy',
      host: ['192.168.1.100'],
      ref: 'origin/main',
      repo: 'git@github.com:user/project.git',
      path: '/opt/app/api',
      'pre-deploy': 'git fetch --all',
      'post-deploy': 'pnpm install && pnpm build && pm2 reload ecosystem.config.js',
      'pre-setup': 'echo "Starting deployment..."',
    },
  },
}
# 首次部署
pm2 deploy production setup

# 后续更新
pm2 deploy production

监控与告警

#
# 终端监控面板
pm2 monit

# 基于 Keymetrics 的 Web 仪表盘(免费额度足够个人项目)
pm2 link <secret> <public-key>

# 自定义指标(在应用代码中)
const io = require('@pm2/io')
io.counter('requests/min').inc()
io.meter('req_rate').mark()
io.histogram('response_time').update(duration)

要接 Prometheus + Grafana 或自建告警,可用 pm2 describe 加日志系统对接外部监控。

常见问题

#

内存泄漏自动重启

max_memory_restart: '500M',   // 达到 500MB 时自动重启

日志时间戳缺失

ecosystem.config.js 里要设 log_date_format,否则日志只有原始文本没有时间。

端口占用

# 找出占用端口的进程
lsof -i :3000
# 或
ss -tlnp | grep 3000
kill -9 <PID>

PM2 命令找不到

# 检查全局 node_modules 路径是否正确
npm root -g
# 如果指向非预期目录,设置 N_PREFIX 或重新安装 Node

pm2 与 systemd 的边界

PM2 本身也是进程。生产环境常见组合是 PM2 管应用、systemd 管 PM2

# 方式一:让 systemd 直接管 Node(应用少时更简单)
# 参考上方 myapp.service 模板,Type=simple + Restart=on-failure

# 方式二:PM2 生成 systemd 自启单元(应用多时)
pm2 startup   # 生成并启用 pm2.service
pm2 save

只有一两个 Node 服务 → 直接 systemd,少一层依赖;多服务、要集群和 pm2 reload → PM2 + pm2 startup。两者不要重复自启,systemd 和 pm2 同时托管会互相拉起。

重启频率过高保护

短时间内反复崩溃时 PM2 会自动停止尝试,避免 crash loop。由 max_restartsrestart_delay 控制:

max_restarts: 10,      // min_uptime 窗口内最多重启次数
restart_delay: 5000,   // 每次重启间隔 5 秒
min_uptime: '30s',     // 运行满 30 秒才视为稳定,重置计数

总结

#

起步三条:pm2 start + pm2 startup + pm2 save 管守护;instances: 'max' + exec_mode: 'cluster' 管多核;ecosystem.config.js + reload 管更新。直接复制上方配置,改 env 和项目名即可。

$ echo "collect what matters, write it down"