1. 为什么你需要PM2?
作为一名Node.js开发者,你一定遇到过这样的场景:当你关闭终端窗口后,辛苦开发的Web服务突然就停止了;或者当服务器内存不足时,应用莫名其妙崩溃;又或者需要同时运行多个Node实例时手忙脚乱。这些痛点正是PM2要解决的核心问题。
PM2是Node.js生态中最流行的进程管理工具,它能让你的Node应用像专业服务一样稳定运行。我最初接触PM2是在2016年维护一个电商后台系统时,当时服务频繁崩溃让我苦不堪言。自从用了PM2,不仅实现了7×24小时稳定运行,还能轻松应对流量高峰时的负载均衡。
与传统的node app.js启动方式相比,PM2提供了以下不可替代的优势:
- 进程守护:自动重启崩溃的应用,就像有个24小时值班的运维
- 日志管理:自动收集和轮转日志,再也不用担心日志文件撑爆磁盘
- 性能监控:实时查看CPU/内存占用,快速定位性能瓶颈
- 集群模式:一行命令启动多进程,充分利用多核CPU性能
- 开机自启:配置一次就能让服务随系统启动,服务器重启也不怕
提示:即使你只是开发小型个人项目,使用PM2也能显著提升开发体验。它就像给Node应用上了保险,让你能专注于业务逻辑而非运维细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与PM2安装
2.1 Node.js环境检查
在安装PM2前,请确保你的系统已安装Node.js环境。打开终端执行以下命令验证:
bash复制node -v
npm -v
如果看到版本号(建议Node.js版本≥12),说明环境已就绪。若未安装,可按以下步骤操作:
Windows系统:
- 访问Node.js官网下载LTS版本安装包
- 双击运行安装向导,保持默认选项
- 安装完成后重新打开命令提示符验证
Mac/Linux系统:
bash复制# 使用Homebrew(Mac)
brew install node
# 使用apt(Ubuntu/Debian)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
2.2 PM2的三种安装方式
根据你的使用场景,可以选择不同的安装方案:
全局安装(推荐):
bash复制npm install pm2 -g
这是最常见的方式,安装后可在任何目录使用pm2命令。适合绝大多数开发和生产环境。
项目本地安装:
bash复制npm install pm2 --save-dev
安装后需要通过npx pm2调用。适合需要严格控制依赖版本的项目,但使用稍显不便。
使用yarn安装:
bash复制yarn global add pm2
与npm全局安装等效,适合习惯yarn的用户。
安装完成后,运行以下命令验证:
bash复制pm2 --version
3. PM2核心功能实战
3.1 基础进程管理
启动应用:
bash复制pm2 start app.js
这个简单的命令背后,PM2其实做了很多工作:
- 创建守护进程监控你的应用
- 建立日志文件存储路径
- 初始化进程状态记录
查看运行列表:
bash复制pm2 list
你会看到类似这样的输出:
code复制┌─────┬───────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├─────┼───────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ app │ default │ N/A │ fork │ 12345 │ 2D │ 0 │ online │ 0% │ 45MB │ yourname │ disabled │
└─────┴───────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
停止应用:
bash复制pm2 stop app
重启应用:
bash复制pm2 restart app
删除应用:
bash复制pm2 delete app
注意:直接使用Ctrl+C或关闭终端不会停止PM2托管的进程,这正是进程守护的核心价值。必须通过PM2命令管理应用生命周期。
3.2 高级配置技巧
实际项目中,我们通常需要更精细的控制。创建一个ecosystem.config.js文件:
javascript复制module.exports = {
apps: [{
name: "my-app",
script: "./app.js",
instances: "max", // 使用所有CPU核心
autorestart: true, // 崩溃自动重启
watch: false, // 关闭文件监听
max_memory_restart: "1G", // 内存超限重启
env: {
NODE_ENV: "development",
},
env_production: {
NODE_ENV: "production",
}
}]
}
启动时指定环境:
bash复制pm2 start ecosystem.config.js --env production
实用参数解析:
--watch:监听文件修改自动重启(开发环境有用,生产环境慎用)--ignore-watch:排除不需要监听的目录,如"node_modules"--log-date-format:自定义日志时间格式--time:为进程添加时间戳日志
3.3 日志管理实战
PM2自动收集日志到~/.pm2/logs目录,包含两种日志:
- 正常输出日志:
app-out.log - 错误日志:
app-error.log
关键日志操作:
bash复制# 实时查看日志
pm2 logs
# 查看特定应用日志
pm2 logs app
# 清空日志
pm2 flush
# 以JSON格式查看日志
pm2 logs --json
日志轮转配置(防止日志文件过大):
bash复制pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 100M # 单个日志文件最大100MB
pm2 set pm2-logrotate:retain 30 # 保留30个日志文件
4. 生产环境最佳实践
4.1 集群模式性能优化
Node.js单线程特性无法充分利用多核CPU,PM2的集群模式可以轻松解决:
bash复制pm2 start app.js -i max
这个命令会根据CPU核心数启动多个实例,PM2会自动做负载均衡。
实测对比:
在我的MacBook Pro (8核)上压力测试:
- 单进程:1200请求/秒
- 集群模式(8实例):7800请求/秒
注意事项:
- 确保应用是无状态的,或已处理好session共享
- 数据库连接池需要适当扩大
- 监控内存使用,每个实例都会消耗独立内存
4.2 开机自启动配置
让PM2管理的应用随系统启动:
bash复制# 生成启动脚本
pm2 startup
# 保存当前进程列表
pm2 save
系统支持情况:
- Linux: systemd/upstart
- MacOS: launchd
- Windows: 需要额外安装pm2-windows-startup
移除自启动:
bash复制pm2 unstartup
4.3 监控与性能调优
PM2内置监控面板:
bash复制pm2 monit
关键性能指标查看:
bash复制pm2 show app
输出包含:
code复制restarts: 0
uptime: 3 hours
script path: /path/to/app.js
script args: N/A
error log path: /home/user/.pm2/logs/app-error.log
out log path: /home/user/.pm2/logs/app-out.log
内存泄漏排查技巧:
- 使用
pm2 logs查看异常日志 - 通过
pm2 describe <id>检查重启次数 - 添加
--max-memory-restart参数预防性重启 - 结合Chrome DevTools做堆内存分析
5. 常见问题解决方案
5.1 权限问题处理
现象:使用sudo启动后,普通用户无法管理进程
解决方案:
bash复制# 修正日志文件权限
sudo chown -R $USER:$USER ~/.pm2
# 或者使用权限绑定
pm2 kill
sudo pm2 unstartup
pm2 startup
5.2 端口冲突问题
当启动多个实例时可能出现端口占用:
javascript复制// 在代码中动态获取端口
const port = process.env.PORT || 3000;
然后在PM2配置中使用环境变量:
javascript复制env: {
PORT: 4000
},
env_production: {
PORT: 5000
}
5.3 环境变量管理
推荐使用dotenv与PM2结合:
- 安装dotenv:
bash复制npm install dotenv
- 创建.env文件:
code复制DB_HOST=localhost
DB_PORT=5432
- 在代码中加载:
javascript复制require('dotenv').config();
- PM2配置:
javascript复制env: {
NODE_ENV: "development",
...require('dotenv').config().parsed
}
5.4 更新PM2版本
保持PM2更新以获得最新功能和安全修复:
bash复制npm install pm2@latest -g
pm2 update
6. 与常见工具集成
6.1 与Docker配合使用
在Dockerfile中的最佳实践:
dockerfile复制FROM node:14
WORKDIR /app
COPY . .
RUN npm install
RUN npm install pm2 -g
CMD ["pm2-runtime", "ecosystem.config.js"]
关键点:
- 使用pm2-runtime作为容器主进程
- 避免在容器内使用后台模式
- 通过环境变量传递配置
6.2 与Nginx反向代理
典型Nginx配置:
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;
}
}
6.3 与CI/CD流程集成
在GitLab CI中的示例:
yaml复制deploy_production:
stage: deploy
script:
- npm install
- npm run build
- pm2 reload ecosystem.config.js --env production
only:
- master
7. 我的实战经验分享
经过多年使用PM2管理各种规模的Node.js应用,总结出以下宝贵经验:
开发环境技巧:
- 使用
pm2-dev启动开发服务器,它结合了PM2的日志功能和nodemon的热重载 - 为不同项目设置不同命名空间避免冲突:
pm2 start app.js --namespace project1 - 通过
pm2 save定期备份进程列表
生产环境教训:
- 一定要设置内存限制,我曾因内存泄漏导致服务器崩溃
- 日志轮转是必须的,有次日志文件占满了整个磁盘
- 慎用
--watch选项,生产环境文件变动可能导致意外重启
性能优化发现:
- 集群模式不是越多越好,超过CPU核心数反而会降低性能
- 适当调整
max_restarts参数防止频繁崩溃时无限重启 - 使用PM2的模块系统可以扩展功能,如
pm2 install pm2-server-monit
最后推荐几个实用命令:
bash复制# 显示应用元信息
pm2 show app
# 生成应用启动脚本
pm2 startup
# 保存当前进程列表
pm2 save
# 从保存的列表恢复
pm2 resurrect
