1. PM2 是什么为什么Node.js开发者离不开它第一次接触PM2是在五年前的一个深夜当时我正在部署一个电商后台服务每次SSH断开连接应用就崩溃直到同事扔给我一行pm2 start app.js。这个看似简单的命令彻底改变了我对Node.js应用部署的认知。PM2本质上是一个Node.js进程管理器但它解决的是生产环境中的核心痛点如何让单线程的Node.js应用具备高可用性。想象你开了一家24小时营业的便利店PM2就是那个永远不会打瞌睡的夜班店员——它不仅能保持应用持续运行还会在应用崩溃时自动重启在流量激增时启动多个收银台集群模式甚至能记录每笔交易的明细日志管理。与直接运行node app.js相比PM2提供了这些关键能力进程守护即使终端关闭或服务器重启应用仍能持续运行负载均衡通过-i参数启动多个实例充分利用多核CPU性能监控实时查看内存/CPU消耗生成可视化报告日志集中管理告别凌乱的console.log输出所有日志统一存储零停机热更新生产环境更新代码时用户无感知我经手过数十个Node.js项目从简单的API服务到日均百万PV的SSR应用PM2始终是部署环节的标准配置。特别是在容器化部署中配合Docker使用能大幅降低进程崩溃导致的容器重启频率。2. 从安装到第一个进程新手避坑指南很多教程会直接告诉你运行npm install -g pm2但根据我的踩坑经验不同环境下安装有这些细节要注意Linux/macOS环境# 不要用root权限安装建议使用nvm管理Node.js环境 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash nvm install --lts npm install pm2latest -gWindows环境特别提示# 需要额外安装windows-startup模块 npm install pm2-windows-startup -g pm2-startup install验证安装时除了看版本号我习惯用这个命令检查关键功能pm2 --version pm2 completion install第一次启动应用时90%的新手会遇到这两个问题路径错误在项目根目录执行pm2 start src/index.js而非pm2 start index.js端口冲突多个实例启动时忘记设置环境变量端口推荐这样启动你的第一个应用# 给应用起名 指定监听端口 pm2 start app.js --name API-Server --env PORT30003. 生产环境实战多进程与性能调优去年优化一个实时聊天服务时单进程架构在500并发时就出现响应延迟。通过PM2的集群模式我们用4核服务器轻松支撑了2000并发# 根据CPU核心数自动启动对应数量的实例 pm2 start app.js -i max但集群模式不是银弹需要注意会话保持需要改用Redis等共享session存储文件上传必须使用云存储或共享磁盘日志关联建议给每个请求添加唯一traceId内存泄漏是Node.js常见问题我的团队曾因为一个未清除的定时器导致服务每天重启3次。通过PM2的内存保护机制完美解决# 当内存超过1GB时自动重启 pm2 start app.js --max-memory-restart 1G对于需要精细控制的场景可以使用生态系统文件// ecosystem.config.js module.exports { apps: [{ name: chat-service, script: dist/server.js, instances: max, exec_mode: cluster, max_memory_restart: 1G, env: { NODE_ENV: production, REDIS_URL: redis://127.0.0.1:6379 } }] }4. 高级运维技巧从日志分析到灾备恢复凌晨三点收到报警发现某API服务CPU占用100%。通过PM2的日志系统快速定位问题# 查看最近1小时的错误日志 pm2 logs --lines 500 --err --timestamp YYYY-MM-DD HH:mm:ss日志分析中我发现一个高频出现的错误堆栈配合pm2 monit确认是某个第三方API调用阻塞了事件循环。临时解决方案是# 限流重启并添加超时保护 pm2 reload api-service --update-env --kill_timeout 3000对于关键业务系统我建议配置这些安全网日志轮转防止日志文件撑爆磁盘pm2 install pm2-logrotate pm2 set pm2-logrotate:max_size 100M健康检查添加HTTP探针// 在生态文件中添加 healthcheck: { url: http://localhost:3000/health, interval: 30 }备份配置定期导出进程列表pm2 save cp ~/.pm2/dump.pm2 ~/backups/5. 性能监控可视化实战去年双十一大促前我们通过PM2 Grafana搭建了完整的监控看板。关键步骤分享安装PM2监控模块pm2 install pm2-prom-exporter配置Prometheus采集指标# prometheus.yml scrape_configs: - job_name: pm2 static_configs: - targets: [your-server-ip:9273]Grafana面板导入ID10991就能看到这样的指标每个进程的Event Loop延迟内存堆使用情况HTTP请求速率/错误率在压力测试中我们发现某个实例的Event Loop延迟明显高于其他实例最终定位到一段同步的JSON解析代码。优化后系统吞吐量提升了40%。6. 容器化部署的最佳实践在Kubernetes环境中使用PM2需要特别注意Dockerfile示例FROM node:18-alpine RUN npm install -g pm2 COPY . . RUN npm install EXPOSE 3000 # 注意不要用pm2-runtime启动 CMD [pm2-runtime, ecosystem.config.js]常见陷阱包括双进程管理同时使用PM2和Kubernetes的副本集会导致资源竞争信号传递容器终止信号需要正确传递给PM2子进程日志收集需要禁用PM2日志写入统一输出到stdout我的经验是开发环境使用PM2集群模式生产环境让K8S管理多个Pod每个Pod只运行单个PM2实例通过--no-daemon参数让PM2运行在前台7. 故障排查从入门到精通遇到PM2异常时我通常会按照这个检查清单排查进程意外退出# 查看退出代码 pm2 show app | grep exit code # 常见代码 # 0: 正常退出 # 1: 未捕获异常 # 137: 内存不足(OOM)CPU占用过高# 生成60秒CPU分析 pm2 profile app 60启动卡住# 查看启动超时设置 pm2 describe app | grep restart delay # 建议配置 kill_timeout: 3000 wait_ready: true listen_timeout: 5000最近遇到一个棘手案例某服务每天固定时段重启。最终通过分析PM2日志发现是cron任务触发了内存泄漏。解决方案是在生态文件中配置cron_restart: 0 3 * * *, // 每天3点主动重启 autorestart: false // 禁用崩溃自动重启记住PM2的黄金法则任何自动重启机制都应该是临时方案根本问题还是要修复代码缺陷。