Back to blog

PM2 Node.js 进程管理方案

从安装配置到生产部署,系统讲解 PM2 的进程管理、日志轮转、集群模式、优雅重启和监控告警。

背景

#

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 是单线程的,一台服务器有多少个 CPU 核心,理论上应该启动多少个 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,始终保持有 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)

也可以直接通过 pm2 describe 和日志系统对接外部监控(Prometheus + Grafana 或自建告警脚本)。

常见问题

#

内存泄漏自动重启

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 默认在短时间内反复崩溃时会自动停止尝试,避免进入 crash loop。通过 max_restartsrestart_delay 控制:

max_restarts: 10,      // 30 秒内最多重启次数
restart_delay: 5000,   // 每次重启间隔 5 秒

总结

#

PM2 的核心配置可以归结为三点:

  1. 进程守护pm2 start + pm2 startup + pm2 save,确保应用随系统启动并在崩溃后自动恢复
  2. 集群模式instances: 'max' + exec_mode: 'cluster',利用多核 CPU
  3. 优雅运维 — 用 ecosystem.config.js 替代命令行,用 reload 替代 restart,用 pm2-logrotate 管理日志

推荐的新项目入口配置模板见上方的 ecosystem.config.js,大多数场景直接复制修改 env 环境变量和项目名称即可使用。

$ echo "collect what matters, write it down"