PM2 基础知识与常用命令总结
PM2 进程管理器使用手册:涵盖安装、启停与重启、日志管理、ecosystem.config.js 配置、cluster 集群模式与开机自启,是 Node.js 应用在生产环境稳定运行的必备工具。
一、PM2 基础概念
1. 什么是 PM2?
- Node.js 进程管理工具
- 生产环境下管理 Node.js 应用的守护进程
- 提供自动重启、负载均衡、日志管理、监控等功能
- 适用于 Node.js 项目(NestJS、Express、Koa、Egg.js 等)
2. 为什么需要 PM2?
| 问题 | 没有 PM2 | 有 PM2 |
|---|---|---|
| 进程崩溃 | 服务直接挂掉,需手动重启 | 自动重启,零停机 |
| 多核利用 | 单进程,浪费 CPU | 集群模式,充分利用多核 |
| 日志管理 | 手动处理,容易丢失 | 自动分日志文件,支持轮转 |
| 开机自启 | 需写 systemd 配置 | 一条命令搞定 |
| 进程监控 | 需额外工具 | 内置监控面板 |
| 环境管理 | 手动切环境变量 | 配置文件统一管理 |
3. PM2 核心特点
- 内建负载均衡:基于 Node.js cluster 模块
- 零停机重启:
pm2 reload逐个重启进程 - 自动重启:进程崩溃或文件变化时自动重启
- 日志系统:stdout/stderr 分离,支持日志轮转
- 生产就绪:支持开机自启、信号处理、优雅关闭
二、安装与环境要求
1. 前置条件
- 已安装 Node.js(建议 16+)
- 已安装 npm
2. 全局安装 PM2
# 全局安装npm install -g pm2# 验证安装pm2 --version# 查看帮助pm2 --help3. 更新 PM2
# 更新 PM2 自身npm install -g pm2@latest# 更新 PM2 后,更新已运行的进程(使其加载新 PM2)pm2 update三、进程管理命令
1. 启动应用
# 基本启动pm2 start app.js# 启动并命名进程pm2 start app.js --name "my-api"# 启动并指定实例数(集群模式)pm2 start app.js -i 4 # 启动 4 个实例pm2 start app.js -i max # 按 CPU 核心数启动pm2 start app.js -i 0 # 同 max# 启动并监听文件变化(开发模式)pm2 start app.js --watch# 启动并指定环境变量pm2 start app.js --env production# 启动并传参pm2 start app.js -- --port 30002. 启动 NestJS 项目
# 编译项目npm run build# 用 PM2 启动编译后的入口文件pm2 start dist/main.js --name "nest-api"# 集群模式启动pm2 start dist/main.js -i max --name "nest-api"# 使用 ts-node 直接启动(开发环境)pm2 start src/main.ts --name "nest-dev" --interpreter ts-node3. 停止进程
# 停止指定进程pm2 stop my-api # 按名称pm2 stop 0 # 按 IDpm2 stop all # 停止所有进程# 停止并从 PM2 列表中删除pm2 delete my-api # 按名称删除pm2 delete 0 # 按 ID 删除pm2 delete all # 删除所有进程4. 重启进程
# 重启(杀掉再启动,有短暂中断)pm2 restart my-apipm2 restart all# 优雅重载(逐个重启,零停机,仅集群模式有效)pm2 reload my-apipm2 gracefulReload my-api # 同上,更明确restart vs reload 的区别:
| 操作 | 行为 | 停机时间 | 适用场景 |
|---|---|---|---|
| restart | 杀掉所有进程,重新启动 | 有 | 单进程、紧急重启 |
| reload | 逐个重启进程 | 零 | 集群模式、生产环境更新 |
5. 进程状态速查
# 查看所有进程pm2 listpm2 ls # 简写# 查看详细信息pm2 show my-api # 查看指定进程详情pm2 info 0 # 按 ID 查看pm2 list 输出示例:
┌────┬──────────────┬─────────────┬──────────┬──────────┬──────────┐│ id │ name │ mode │ ↺ │ status │ cpu │├────┼──────────────┼─────────────┼──────────┼──────────┼──────────┤│ 0 │ nest-api │ cluster │ 2 │ online │ 0.5% ││ 1 │ nest-worker │ fork │ 0 │ online │ 0.3% │└────┴──────────────┴─────────────┴──────────┴──────────┴──────────┘| 字段 | 说明 |
|---|---|
| id | 进程 ID |
| name | 进程名称 |
| mode | 运行模式(fork=单进程,cluster=集群) |
| ↺ | 重启次数 |
| status | 状态(online/errored/stopped) |
| cpu | CPU 占用率 |
四、监控与调试
1. 实时监控面板
# 打开终端监控面板(类似 top 命令)pm2 monit监控面板包含:
- 进程列表(CPU、内存使用率)
- 实时日志输出
- 左右切换面板
2. 查看日志
# 查看所有进程日志pm2 logs# 查看指定进程日志pm2 logs my-api# 只看最近 50 行pm2 logs my-api --lines 50# 实时监听日志(默认行为)pm2 logs my-api# 只看错误日志pm2 logs my-api --err# 只看输出日志pm2 logs my-api --out# 清空所有日志pm2 flush# 清空指定进程日志pm2 flush my-api3. 查看进程资源消耗
# 查看所有进程的 CPU 和内存pm2 prettylist # JSON 格式详细信息# 查看指定进程详情pm2 describe my-apipm2 desc 0 # 简写pm2 describe 输出包含:
- 进程路径、启动参数
- 运行时间、重启次数
- 内存使用(RSS、heap used、heap total)
- 日志文件路径
- 执行模式、PID
五、配置文件(ecosystem.config.js)
1. 创建配置文件
# 生成配置文件模板pm2 initpm2 ecosystem # 同上2. 完整配置示例
// ecosystem.config.jsmodule.exports = { apps: [ { name: 'nest-api', // 进程名称 script: 'dist/main.js', // 入口文件 instances: 'max', // 实例数(max=CPU核心数,或数字) exec_mode: 'cluster', // 运行模式(cluster/fork) cwd: './', // 工作目录 watch: false, // 是否监听文件变化 env: { // 默认环境变量(开发) NODE_ENV: 'development', PORT: 3000, DB_HOST: 'localhost', DB_PORT: 3306, DB_NAME: 'miracle_dev', }, env_production: { // 生产环境变量 NODE_ENV: 'production', PORT: 3000, DB_HOST: '127.0.0.1', DB_PORT: 3306, DB_NAME: 'miracle', REDIS_HOST: '127.0.0.1', REDIS_PORT: 6379, }, // 日志配置 out_file: './logs/out.log', // 标准输出日志 error_file: './logs/error.log',// 错误日志 merge_logs: true, // 集群模式下合并日志 log_date_format: 'YYYY-MM-DD HH:mm:ss', // 日志加时间戳 // 重启策略 max_restarts: 10, // 最大重启次数 restart_delay: 3000, // 重启间隔(毫秒) max_memory_restart: '1G', // 内存超过 1G 自动重启 // 优雅关闭 kill_timeout: 3000, // 发送 kill 信号后等待时间 listen_timeout: 8000, // 启动超时时间 }, // 可以配置多个应用 { name: 'nest-worker', // 另一个进程(如消息队列消费者) script: 'dist/worker.js', instances: 1, exec_mode: 'fork', env_production: { NODE_ENV: 'production', }, }, ],};3. 使用配置文件启动
# 使用配置文件启动(默认环境)pm2 start ecosystem.config.js# 使用生产环境配置启动pm2 start ecosystem.config.js --env production# 重启配置文件中的所有应用pm2 restart ecosystem.config.js --env production# 重载(零停机)pm2 reload ecosystem.config.js --env production# 停止pm2 stop ecosystem.config.js# 删除pm2 delete ecosystem.config.js4. 常用配置项速查
| 配置项 | 类型 | 说明 |
|---|---|---|
| name | string | 进程名称 |
| script | string | 入口文件路径 |
| instances | number/string | 实例数(max/数字) |
| exec_mode | string | cluster 或 fork |
| cwd | string | 工作目录 |
| watch | boolean/string | 文件监听(可指定目录) |
| env | object | 默认环境变量 |
| env_production | object | 生产环境变量 |
| env_development | object | 开发环境变量 |
| out_file | string | 输出日志路径 |
| error_file | string | 错误日志路径 |
| merge_logs | boolean | 合并集群日志 |
| log_date_format | string | 日志时间戳格式 |
| max_restarts | number | 最大重启次数 |
| restart_delay | number | 重启延迟(毫秒) |
| max_memory_restart | string | 内存超限自动重启 |
| kill_timeout | number | 优雅关闭超时 |
| listen_timeout | number | 启动就绪超时 |
六、集群模式
1. 集群模式 vs Fork 模式
| 维度 | fork 模式 | cluster 模式 |
|---|---|---|
| 进程数 | 单进程 | 多进程(按 CPU 核心) |
| 多核利用 | 否 | 是 |
| 负载均衡 | 无 | 内置(轮询) |
| 零停机重载 | 不支持 | 支持(reload) |
| 共享端口 | 不支持 | 支持(自动共享) |
| 适用场景 | 定时任务、消费者 | Web 服务、API 服务 |
2. 启动集群模式
# 按 CPU 核心数启动pm2 start dist/main.js -i max --name "nest-api"# 指定实例数pm2 start dist/main.js -i 4 --name "nest-api"# 在配置文件中指定module.exports = { apps: [{ name: 'nest-api', script: 'dist/main.js', instances: 'max', // 集群模式 exec_mode: 'cluster', }],};3. 集群模式下的操作
# 零停机重载(逐个重启)pm2 reload nest-api# 查看集群状态pm2 list # mode 列显示 cluster# 增减实例数(需要先 delete 再重新 start)pm2 delete nest-apipm2 start ecosystem.config.js --env production4. 集群模式注意事项
- 共享端口:所有实例共享同一个端口(如 3000),PM2 自动处理
- Session 问题:集群模式下 Session 不能存在内存中,必须用 Redis 存储
- WebSocket:长连接会固定在某个实例上,需要用 Redis Pub/Sub 跨实例通信
- 文件操作:多实例同时写文件会冲突,需用锁机制或由单独的 worker 处理
七、日志管理
1. 日志文件位置
默认日志路径:~/.pm2/logs/
~/.pm2/logs/├── nest-api-out.log # 标准输出日志├── nest-api-error.log # 错误日志├── nest-worker-out.log└── nest-worker-error.log2. 自定义日志路径
在配置文件中指定:
{ out_file: './logs/out.log', error_file: './logs/error.log', log_date_format: 'YYYY-MM-DD HH:mm:ss', merge_logs: true,}3. 日志轮转(logrotate)
PM2 自带日志轮转模块:
# 安装日志轮转模块pm2 install pm2-logrotate# 查看当前配置pm2 conf pm2-logrotate# 修改配置pm2 set pm2-logrotate:max_size 10M # 单个日志文件最大 10Mpm2 set pm2-logrotate:retain 30 # 保留 30 个日志文件pm2 set pm2-logrotate:compress true # 压缩旧日志pm2 set pm2-logrotate:dateFormat YYYY-MM-DD # 日志文件日期格式pm2 set pm2-logrotate:workerInterval 30 # 检查间隔(秒)pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # 每天午夜轮转4. 日志命令汇总
pm2 logs # 查看所有日志(实时)pm2 logs my-api # 查看指定进程日志pm2 logs my-api --lines 100 # 查看最近 100 行pm2 logs my-api --err # 只看错误日志pm2 flush # 清空所有日志pm2 flush my-api # 清空指定进程日志八、开机自启动
1. 生成开机自启脚本
# 保存当前 PM2 进程列表(必须先执行,再设置自启)pm2 save# 生成并安装系统启动脚本pm2 startup # 自动检测系统类型# 指定系统类型pm2 startup systemd # Linux systemdpm2 startup launchd # macOSpm2 startup upstart # Ubuntu 老版本执行 pm2 startup 后会输出一条命令,复制执行即可:
# 输出示例(需要复制执行)[PM2] To setup the Startup Script, copy/paste the following command:sudo env PATH=$PATH:/usr/local/bin pm2 startup systemd -u youruser --hp /home/youruser2. 保存与恢复进程列表
# 保存当前运行的进程列表pm2 save# 手动恢复(通常开机自启会自动执行)pm2 resurrect# 查看保存的进程列表cat ~/.pm2/dump.pm23. 取消开机自启
# 取消开机自启pm2 unstartup# 指定系统类型取消pm2 unstartup systemd4. 完整流程(首次配置)
# 1. 启动你的应用pm2 start ecosystem.config.js --env production# 2. 保存进程列表pm2 save# 3. 设置开机自启(复制输出的命令执行)pm2 startup# 4. 完成,重启服务器验证sudo reboot九、生产环境实战配置
1. NestJS 项目完整配置
// ecosystem.config.jsmodule.exports = { apps: [ { name: 'nest-api', script: 'dist/main.js', instances: 'max', exec_mode: 'cluster', // 生产环境变量 env_production: { NODE_ENV: 'production', PORT: 3000, }, // 日志 out_file: '/var/log/nest-api/out.log', error_file: '/var/log/nest-api/error.log', merge_logs: true, log_date_format: 'YYYY-MM-DD HH:mm:ss Z', // 自动重启策略 max_restarts: 10, restart_delay: 3000, max_memory_restart: '1G', // 优雅关闭 kill_timeout: 5000, listen_timeout: 10000, }, ],};2. 部署流程
# 1. 拉取最新代码git pull origin main# 2. 安装依赖npm install# 3. 编译npm run build# 4. 零停机重载pm2 reload ecosystem.config.js --env production# 5. 确认状态pm2 listpm2 logs nest-api --lines 203. 一键部署脚本
#!/bin/bash# deploy.shset -eecho "==> 拉取代码..."git pull origin mainecho "==> 安装依赖..."npm install --production=falseecho "==> 编译项目..."npm run buildecho "==> 重载 PM2(零停机)..."pm2 reload ecosystem.config.js --env productionecho "==> 保存进程列表..."pm2 saveecho "==> 部署完成!"pm2 list使用方式:
chmod +x deploy.sh./deploy.sh十、常用命令速查表
进程管理
| 命令 | 说明 |
|---|---|
pm2 start app.js |
启动应用 |
pm2 start app.js --name "myapp" |
启动并命名 |
pm2 start app.js -i max |
集群模式启动 |
pm2 start app.js --watch |
文件变化自动重启 |
pm2 stop myapp |
停止进程 |
pm2 stop all |
停止所有进程 |
pm2 restart myapp |
重启进程 |
pm2 reload myapp |
零停机重载(集群模式) |
pm2 delete myapp |
停止并删除进程 |
pm2 delete all |
删除所有进程 |
查看状态
| 命令 | 说明 |
|---|---|
pm2 list |
查看进程列表 |
pm2 show myapp |
查看进程详情 |
pm2 monit |
实时监控面板 |
pm2 describe myapp |
查看详细信息 |
pm2 prettylist |
JSON 格式查看所有进程 |
日志
| 命令 | 说明 |
|---|---|
pm2 logs |
查看所有日志 |
pm2 logs myapp |
查看指定进程日志 |
pm2 logs myapp --lines 50 |
查看最近 50 行 |
pm2 logs myapp --err |
只看错误日志 |
pm2 flush |
清空所有日志 |
配置与自启
| 命令 | 说明 |
|---|---|
pm2 init |
生成配置文件模板 |
pm2 start ecosystem.config.js |
用配置文件启动 |
pm2 start ecosystem.config.js --env production |
用生产环境配置启动 |
pm2 save |
保存当前进程列表 |
pm2 startup |
设置开机自启 |
pm2 unstartup |
取消开机自启 |
pm2 resurrect |
恢复保存的进程列表 |
模块管理
| 命令 | 说明 |
|---|---|
pm2 install pm2-logrotate |
安装模块 |
pm2 uninstall pm2-logrotate |
卸载模块 |
pm2 list |
也可查看已安装模块 |
pm2 conf |
查看模块配置 |
十一、常见面试题
基础概念
Q1:PM2 是什么?解决了什么问题?
- Node.js 生产环境进程管理工具
- 解决 Node.js 单进程崩溃后无法自动恢复的问题
- 提供集群模式实现多核负载均衡
- 提供日志管理、监控、开机自启等生产级功能
Q2:PM2 的 fork 模式和 cluster 模式有什么区别?
| 维度 | fork | cluster |
|---|---|---|
| 进程数 | 1 个 | 多个(按 CPU 核心) |
| 多核利用 | 否 | 是 |
| 负载均衡 | 无 | 内置轮询 |
| 共享端口 | 否 | 是 |
| 零停机重载 | 不支持 | 支持 |
| 适用场景 | 消费者、定时任务 | Web 服务 |
Q3:pm2 restart 和 pm2 reload 有什么区别?
- restart:杀掉所有进程再重新启动,有短暂停机
- reload:逐个重启进程,实现零停机,仅 cluster 模式有效
- 生产环境更新代码应使用 reload
进阶问题
Q4:PM2 集群模式下如何处理 Session?
- 集群模式有多个进程实例,内存中的 Session 不共享
- 必须将 Session 存储到外部(如 Redis)
- NestJS 中用
@nestjs-modules/ioredis或connect-redis实现
Q5:PM2 集群模式下 WebSocket 怎么处理?
- WebSocket 长连接会固定在某一个实例上
- 跨实例通信需要用 Redis Pub/Sub
- 或者使用第三方服务(如腾讯云 IM)来处理实时通信
Q6:如何实现 PM2 的零停机部署?
# 1. 编译新代码npm run build# 2. 零停机重载pm2 reload ecosystem.config.js --env production- reload 会逐个重启实例,总有一个实例在处理请求
- 前提是 cluster 模式且 instances > 1
Q7:PM2 的 max_memory_restart 是怎么工作的?
- PM2 定期检查进程内存使用量
- 超过设定值时自动重启该进程
- 防止内存泄漏导致服务器崩溃
- 示例:
max_memory_restart: '1G'
Q8:PM2 如何实现开机自启动?
pm2 startup生成系统启动脚本(systemd/launchd)pm2 save保存当前进程列表到~/.pm2/dump.pm2- 系统启动时自动执行 PM2,恢复保存的进程列表
实战经验
Q9:PM2 启动后进程频繁重启怎么办?
- 检查错误日志:
pm2 logs myapp --err - 常见原因:
- 端口被占用
- 环境变量缺失
- 代码有语法错误
- 依赖未安装
- 检查
restart_delay设置,避免重启风暴
Q10:如何查看 PM2 进程的实际 PID?
pm2 describe myapp | grep pid# 或pm2 prettylist | grep pidQ11:PM2 日志文件越来越大怎么办?
- 安装
pm2-logrotate模块实现日志轮转 - 设置
max_size(如 10M)自动切割 - 设置
retain(如 30)限制保留数量 - 或用 Linux 的 logrotate 工具管理
Q12:如何在不停止服务的情况下更新代码?
# 方式1:文件监听模式(开发环境)pm2 start app.js --watch# 方式2:编译后 reload(生产环境推荐)npm run buildpm2 reload ecosystem.config.js --env production十二、常见问题与注意事项
1. 端口被占用
# 查看端口占用lsof -i :3000 # Linux/Macnetstat -ano | findstr :3000 # Windows# 杀掉占用进程kill -9 <PID># 重新启动pm2 start ecosystem.config.js --env production2. PM2 命令找不到
# PM2 全局安装路径没在 PATH 中npm install -g pm2# 查找 PM2 路径which pm2# 或npm root -g# 手动创建软链接ln -s /usr/local/lib/node_modules/pm2/bin/pm2 /usr/local/bin/pm23. 集群模式下内存泄漏
// 在配置文件中设置内存上限自动重启{ max_memory_restart: '1G',}同时要排查代码中的内存泄漏:
- 未清除的定时器
- 闭包引用
- 全局变量无限增长
- 事件监听器未移除
4. 日志时区问题
// 在配置文件中设置时区格式{ log_date_format: 'YYYY-MM-DD HH:mm:ss Z', // 或使用本地时间 tz: 'Asia/Shanghai',}5. 优雅关闭(Graceful Shutdown)
NestJS 中需要处理 PM2 发送的关闭信号:
// main.tsimport { NestFactory } from '@nestjs/core';async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); // 优雅关闭 process.on('SIGINT', async () => { await app.close(); process.exit(0); }); process.on('SIGTERM', async () => { await app.close(); process.exit(0); });}bootstrap();PM2 配置中设置关闭超时:
{ kill_timeout: 5000, // 给应用 5 秒时间优雅关闭}6. 环境变量管理
# 直接在命令行传环境变量PORT=3000 pm2 start dist/main.js --name "nest-api"# 在配置文件中管理(推荐)module.exports = { apps: [{ name: 'nest-api', script: 'dist/main.js', env_production: { PORT: 3000, DB_HOST: '127.0.0.1', }, }],};# 使用 .env 文件(配合 dotenv)// 在 NestJS 中通过 @nestjs/config 读取 .env 文件十三、总结
PM2 是 Node.js 生产环境部署的标配工具,核心能力:
| 能力 | 说明 |
|---|---|
| 进程守护 | 崩溃自动重启 |
| 集群模式 | 多核负载均衡 |
| 零停机部署 | reload 逐个重启 |
| 日志管理 | stdout/stderr 分离 + 轮转 |
| 监控 | 内置 CPU/内存监控 |
| 开机自启 | 一条命令搞定 |
生产环境最佳实践:
- 用
ecosystem.config.js管理配置,不要裸命令启动 - 用
--env production区分环境 - 用
reload而非restart做更新 - 用
pm2-logrotate管理日志大小 - 用
pm2 save+pm2 startup设置开机自启 - 用
max_memory_restart防止内存泄漏 - 集群模式下 Session 和 WebSocket 走 Redis