PM2 生产环境进程管理:从零停机部署到常见故障排查

主题: pm2-cluster-mode-port-already-in-use更新于: 2026/6/27作者:AgentFactory 技术团队

PM2 是 Node.js 应用最成熟的生产级进程管理器。它解决了开发者在生产环境中面临的几个核心痛点:应用崩溃后自动恢复、利用多核 CPU 提升吞吐量、零停机更新代码、以及统一的日志和监控。本文聚焦于实战配置、参数详解和典型报错排查,避免空泛介绍。

安装与快速上手

全局安装 PM2 后,即可启动任意 Node.js 脚本。

BASH
npm install pm2@latest -g

启动一个应用:

BASH
pm2 start app.js --name my-api

查看进程状态:

BASH
pm2 list

查看实时日志:

BASH
pm2 logs my-api

停止并删除进程:

BASH
pm2 stop my-api && pm2 delete my-api

核心参数详解与配置示例

PM2 的灵活性体现在丰富的启动参数上。以下表格列出最常用的参数及其生产环境典型用法。

参数是否必填说明生产环境建议
--name指定应用名称,便于管理始终使用,避免混淆
--watch监听文件变化并自动重启生产环境禁用,避免意外重启
--max-memory-restart设置内存阈值,超过后自动重启(如 <200MB>建议设置,防止内存泄漏耗尽服务器
--log指定日志文件路径配合 pm2-logrotate 使用,避免磁盘写满
--restart-delay自动重启前的延迟(毫秒)建议设置 3000-5000ms,给应用初始化时间
--time在日志行前添加时间戳建议启用,便于问题定位
--no-autorestart禁止自动重启仅用于调试,生产环境不要使用
--cron指定 cron 表达式强制重启可用于定期清理内存泄漏
--no-daemon前台运行(不后台化)仅用于调试
-i启用集群模式,指定实例数(0/max 表示所有 CPU,-1 表示所有 CPU 减 1)多核服务器建议使用 -i max
--no-vizion禁用版本控制集成如果不需要版本信息,建议禁用以提升性能

生产环境启动示例

BASH
pm2 start app.js \
  --name production-api \
  -i max \
  --max-memory-restart 200M \
  --restart-delay 5000 \
  --time \
  --no-vizion

Ecosystem File(推荐)

对于复杂配置,建议使用 ecosystem.config.js 文件统一管理。

JAVASCRIPT
module.exports = {
  apps: [{
    name: 'production-api',
    script: './app.js',
    instances: 'max',
    exec_mode: 'cluster',
    max_memory_restart: '200M',
    restart_delay: 5000,
    time: true,
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
};

启动方式:

BASH
pm2 start ecosystem.config.js

与同类方案对比

特性PM2forevernodemonsystemd
进程保活❌(开发用)
集群模式(多核)✅ 内置
零停机重载pm2 reload
内置监控pm2 monit
启动脚本pm2 startup✅ 原生
配置复杂度极低
日志管理✅ 内置 + 插件
扩缩容pm2 scale

结论forevernodemon 功能过于简单,不适合生产环境。systemd 是系统级工具,配置繁琐且缺乏应用级特性。PM2 在单机或小规模部署场景下是最优选择。对于大规模容器化部署,应使用 Docker/K8s。

生产环境实践与注意事项

1. 无状态应用要求

PM2 集群模式使用轮询算法分发请求。如果应用在内存中存储 Session、WebSocket 连接或本地缓存,不同进程间的数据会不一致。

解决方案:使用外部存储共享状态,例如 Redis 存储 Session。

JAVASCRIPT
const session = require('express-session');
const RedisStore = require('connect-redis')(session);

app.use(session({
  store: new RedisStore({ host: 'localhost', port: 6379 }),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false
}));

2. 文件锁定与并发写入

多个工作进程同时写入同一个文件可能导致数据损坏。

解决方案:使用专门的日志库(如 winston 配合 file 传输)或数据库处理并发写入。

3. 端口冲突

在集群模式下,PM2 会自动共享端口。不要手动指定 --port 参数,否则每个进程会尝试监听不同端口。

4. 内存泄漏处理

--max-memory-restart 可以自动重启超过内存阈值的进程,但无法修复根本原因。建议结合 heapdump 分析内存快照。

5. 安全建议

  • 不要以 root 用户运行 PM2,创建专用用户(如 node)。
  • 使用 pm2 startup 时确保脚本权限正确。
  • 安装 pm2-logrotate 限制日志文件大小:pm2 install pm2-logrotate
  • 生产环境禁用 --watch

6. 服务器重启后自动恢复

BASH
# 生成启动脚本(以非 root 用户运行)
pm2 startup

# 保存当前进程列表
pm2 save

重启服务器后,使用 pm2 list 验证进程是否自动恢复。

常见报错与排查

错误 1:Error: listen EADDRINUSE :::3000

原因:端口 3000 已被占用。

解决步骤

  1. 查找占用进程:lsof -i :3000netstat -tulpn | grep 3000
  2. 终止进程:kill -9 <PID>
  3. 如果是在集群模式下,确保没有手动指定 --port 参数。

错误 2:PM2: Script '/path/to/app.js' had too many unstable restarts (16). Stopped. "errored"

原因:应用启动后立即崩溃,PM2 停止尝试重启。

解决步骤

  1. 查看详细错误日志:pm2 logs <app-name>
  2. 手动运行 node app.js 测试应用是否能正常启动。
  3. 增加 --restart-delay 参数,给应用更多初始化时间。

错误 3:PM2: Cannot find module '/path/to/app.js'

原因:PM2 找不到指定的脚本文件。

解决步骤

  1. 确认脚本路径是否正确,使用绝对路径或相对于 PM2 工作目录的路径。
  2. 使用 pwd 查看当前工作目录,然后使用 ls 确认文件是否存在。
  3. 在 Ecosystem File 中设置 cwd 选项指定工作目录。

错误 4:PM2: Error: listen EACCES :::80

原因:没有权限监听 80 端口(需要 root 权限)。

推荐解决方案:使用 Nginx 作为反向代理,监听 80 端口,将请求转发到 PM2 管理的应用端口(如 3000)。

NGINX
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

不推荐:使用 sudo pm2 start app.js(存在安全风险)。

常见问题 FAQ

Q: PM2 的 restartreload 有什么区别?什么时候该用哪个?

A: restart 会立即杀死所有工作进程,然后重新启动它们,导致短暂停机。reload 逐个重启工作进程,实现零停机。

  • 开发环境或允许短暂停机:使用 restart
  • 生产环境:使用 reload

注意reload 要求应用无状态,并正确处理 SIGINT 信号。如果超时未关闭,PM2 会回退到 restart

Q: 如何让 PM2 管理的应用在服务器重启后自动启动?

A: 使用 pm2 startuppm2 save

  1. 生成启动脚本:pm2 startup
  2. 保存当前进程列表:pm2 save

如果遇到权限问题,可以尝试:

BASH
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u <your-username> --hp /home/<your-username>

Q: PM2 集群模式下,如何确保多个进程之间的 Session 共享?

A: 使用外部 Session 存储,如 Redis、MongoDB 或数据库。示例(Express + Redis)见上文“无状态应用要求”部分。

相关深度解决方案

在配置当前服务时,如果您遇到了数据库锁死或需要更高并发的读写控制,建议配合参考我们整理的 SQLite MCP 服务的高级缓存配置指南 来提升响应速度。