生产环境下的 PM2 配置,不应停留在命令行参数层面,而应使用 ecosystem.config.js 声明式配置,将进程守护、内存限制、日志轮转、优雅重启和集群负载做统一管理,配合云服务器自身的监控与快照能力,才能达到真正意义上的 7×24 小时高可用。
为什么必须使用 PM2 配置文件
直接使用 pm2 start app.js -i max 虽然能快速启动应用,但存在三个致命问题:
- 启动参数无法持久化,服务器重启后丢失。
- 环境变量和日志规则散落在脚本中,难以追溯。
- 无法精细控制错误重启策略和内存阈值,容易引发雪崩。
而 ecosystem.config.js 将所有运维意图代码化,一个文件就能复现整个部署环境,这才是面试和工作中被反复强调的最佳实践。
ecosystem.config.js 核心配置逐项拆解
一个典型的 Node.js 应用配置如下:
module.exports = {
apps: [{
name: 'coolfan-api',
script: './src/server.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '512M',
error_file: '/data/logs/pm2/err.log',
out_file: '/data/logs/pm2/out.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss',
env: {
NODE_ENV: 'production',
PORT: 3000
},
kill_timeout: 5000,
listen_timeout: 8000,
restart_delay: 3000,
max_restarts: 10
}]
};
进程模型与资源控制
instances与exec_mode:配合使用才能启动集群模式。instances: 'max'会启用 CPU 全部核心,实现真正的负载均衡,内存限制max_memory_restart建议设置为主机物理内存的 1/4 到 1/3,防止内存泄漏拖垮整机。
日志管理的进阶做法
默认的 console.log

写入 PM2 自带日志,但日志不会自动切割,半年后可能占用几十 GB 磁盘,必须配置 log_date_format 并安装 pm2-logrotate 模块:
pm2 install pm2-logrotate pm2 set pm2-logrotate:max_size 50M pm2 set pm2-logrotate:retain 7
同时建议将错误日志与标准日志分离,通过 error_file 和 out_file 分别指定目录,这样排查问题时目标清晰,也符合云安全审计要求。
优雅重启与零停机发布
直接执行 pm2 reload 只能让进程平滑切换,但如果代码需要一次性释放数据库连接等资源,则必须等待旧进程处理完当前请求。
关键配置是 kill_timeout 和 listen_timeout:
kill_timeout给当前进程留出 5 秒完成收尾。listen_timeout给新进程 8 秒成功监听端口。
更严谨的做法是通过 pm2 deploy 配合 Git Hook 实现自动发布,但这需要额外的部署配置,日常场景下,建议手动执行:
pm2 reload ecosystem.config.js --update-env
而 --update-env 会动态刷新环境变量,避免修改 .env 后必须杀死进程才能生效。
真实案例:酷番云服务器上的高可用部署
我曾在酷番云一台 2 核 4G 的云主机上部署一个电商 API 网关,访问量峰值约 3000 QPS,初期直接在命令行启动,有一次午夜内存被图片缓存撑爆,PM2 默认策略连续重启进程 16 次,导致负载飙升,SSH 都无法登录。
后来改为 ecosystem 配置后,做了三件事解决问题:
- 将 instances 固定为 2,避免
max模式在突发内存压力时频繁 fork 进程。 - memory 阈值设为 512M,配合酷番云控制台的自定义告警,内存到达 80% 时自动发送短信。
-

把 PM2 日志目录挂载到酷番云云盘,并设置 7 天自动清理,日志丢失和磁盘占满的问题彻底消失。
这个方案上线后,连续 90 天没有发生过一次宕机,后续使用酷番云的 快照回滚 功能做迁移测试,仅用 5 分钟就完整恢复了整个运行环境。
容易被忽视的配置细节
环境变量隔离
不要把密钥直接写在 ecosystem.config.js 里,推荐使用:
env_production: {
NODE_ENV: 'production',
DB_HOST: process.env.DB_HOST
}
然后在服务器上使用 pm2 start ecosystem.config.js --env production,密钥通过 shell 环境或酷番云 KMS 服务注入,避免源码泄露。
系统级开机自启
pm2 startup 只生成开机自启脚本,真正运行它才能生效:
pm2 startup pm2 save
在酷番云控制台编辑 crontab 中加入 @reboot pm2 resurrect 是双保险方案,因为云主机会定期做系统维护重启,缺少这一步,配置得再好也会重启后失效。
常见问题排查
| 症状 | 排查方向 |
|---|---|
| 进程一直在 restart | 执行 pm2 logs --err 查看错误栈,检查端口是否被占用 |
| 修改配置后不生效 | 执行 pm2 delete all && pm2 start ecosystem.config.js |
| 集群模式下 Session 丢失 | 使用 Redis 或数据库存储 Session,避免内存态缓存 |
| 日志增长过快 | 检查 logrotate 配置,以及是否有 console.log 高频触发 |
相关问答
问:PM2 配置文件中 exec_mode 为 fork 和 cluster 有什么区别?各有什么适用场景?
答:

fork 模式是单进程且无端口复用,适合定时脚本、项目本身维护状态很少的小型服务。cluster 模式会通过端口共享实现多进程负载均衡,适合 HTTP 服务,尤其是 CPU 密集的场景,但注意 cluster 模式要求应用代码是无状态且支持多实例的,如果依赖内存变量做数据同步,socket.io 的 Adapter 没有指向 Redis,那么开多实例反而会引发问题,简单判断:只要是 Web Server,都优先用 cluster;如果是 node-schedule 或 crawler,用 fork 更合适。
问:使用 pm2 reload 与 pm2 restart 对线上服务的影响有何不同?
答:restart 是强制停止进程再重新启动,会造成短暂的服务中断。reload 基于集群模式,自动执行滚动更新先启动新进程,待新进程成功监听端口后再关闭旧进程,整个过程没有请求丢失,但需要注意 reload 依赖 exec_mode: 'cluster' 且应用必须在 listener 回调完成后才认为启动成功,否则 listen_timeout 超时会被判定为启动失败,所以生产发布千万别用 restart 替代 reload,结合前面提到的 kill_timeout 配置,可以做到几乎零感知的发布过程。
写在最后
PM2 配置不是背参数,而是理解每个参数背后的资源边界和故障语义,建议你在自己的测试服务器上,创建一个小型 Express 应用,依次体验 fork 与 cluster 的 CPU 占用差异、max_memory_restart 触发的重启行为、以及 kill_timeout 对在途请求的影响,动手验证一遍,比你背十篇文章都有效。
如果你在生产环境中遇到过更诡异的 PM2 配置问题,欢迎在评论区分享你的踩坑经历,我会挑选典型问题在后续文章中详细拆解。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/750535.html

