Skip to content

核心概念与工作原理

定位:建立正确的心智模型。不理解这一篇,后面所有命令都只是"背用法";理解了这一篇,PM2 的每个命令都变得"理所当然"。
前置:已按 概述 完成安装。

一句话模型

PM2 = 一个常驻的"监护人"进程(daemon)+ 一群由它拉起、看护的"被管理进程" + 一个命令行遥控器(CLI)。

你执行 pm2 start app.js 时,真正发生的事情是:

  1. CLI 向 daemon(守护进程)发出 RPC 请求:"请帮我把 app.js 拉起来";
  2. daemon 以 子进程 方式启动 app.js(默认 fork 模式:node app.js);
  3. daemon 从此"盯"着它:进程退出就按策略重启、记录日志、统计 CPU/内存、响应你的管理指令。

所以 pm2 start app.js 执行完,命令就返回了——你的终端可以关掉,服务照样在跑,因为真正干活的是 daemon,不是你的终端。

你的终端                    后台
┌─────────────┐   RPC   ┌──────────────────────────┐
│  pm2 CLI    │ ──────▶ │  PM2 daemon (God 进程)    │
│  start/ls/  │ ◀────── │  - 看护/重启/记录日志      │
│  restart... │         │  - 持有每个进程的状态       │
└─────────────┘         └──────────┬───────────────┘
                                  │ fork / 管理
                           ┌──────┴────────┐
                           │  你的应用进程   │  (node app.js)
                           │  app-0        │
                           │  app-1 (cluster)│
                           └───────────────┘

三个角色的区分(最容易混淆的点)

角色是什么谁启动的特征
PM2 daemonPM2 自己的主进程第一次执行 pm2 命令时自动启动后台运行、每用户一个、退出后所有被管理进程失去看护
被管理进程你的 Node 应用daemon 代为启动是 daemon 的子进程
pm2 CLI命令行工具你每次敲命令时临时运行执行完即退出,只是"遥控器"

理解要点:

  • daemon 挂了,进程未必立刻挂,但会失去"看护":孤儿进程仍在跑,但没人再负责崩溃重启、日志、状态汇报。所以生产环境要保证 daemon 本身也活着(→ 开机自启与远程部署,用 systemd 托管 daemon)。
  • daemon 是按用户隔离的:daemon 与它所托管的进程属于同一系统用户、同一个 PM2_HOME(默认 ~/.pm2)。用 root 跑的应用和用 www 用户跑的应用互不可见,也无法互相管理。
  • 换用户 = 换了一个世界sudo pm2 ls 看到的是 root 的 daemon 列表,跟你自己的 pm2 ls 完全是两回事。

目录结构:~/.pm2(PM2_HOME)

daemon 的所有“记忆”都落在 PM2_HOME 目录下(默认 $HOME/.pm2,可用环境变量 PM2_HOME 改到别处,例如 /var/run/pm2 或容器卷):

路径内容
~/.pm2/pm2.piddaemon 的 PID(可用于确认 daemon 在跑)
~/.pm2/pm2.logPM2 自身的运行日志(不是你的应用日志!)
~/.pm2/pm2.sockrpc.sockpub.sockCLI 与 daemon 通信用的 Unix socket
~/.pm2/logs/应用日志默认落盘位置(见下)
~/.pm2/pids/每个被管理进程的 PID 文件
~/.pm2/dump.pm2pm2 save 生成的进程清单快照(重启 daemon / 开机自启靠它)
~/.pm2/module_conf.jsonPM2 模块(如 pm2-logrotate)的配置

排查"PM2 怎么怪怪的"第一站:看 ~/.pm2/pm2.log注意别和应用日志搞混——应用打印的 console 日志默认落在 ~/.pm2/logs/ 下(默认文件名形如 <app>-out-<pid>.log / <app>-error-<pid>.log,详见 日志与轮转)。

进程的"身份"与命名

PM2 里每个被管理进程同时拥有:

  • name(应用名):你起的别名(pm2 start app.js --name web → name = web)。可以多个实例共用同一个 name。
  • id(数字 ID):PM2 内部从 0 开始分配的编号。pm2 start 输出表格里的 id 列;pm2 describe 0pm2 restart 0 都可用。
  • namespace(命名空间):逻辑分组(如 backend/frontend),用于列表过滤与成组操作(pm2 ls --namespace backend 等);ecosystem 配置项与 CLI 支持程度随版本而异,以本机帮助为准。

日常习惯:

  • 与人沟通、写文档:用 name
  • 脚本里自动化:优先用 name(id 会随删除/重启变动,name 稳定);
  • name 冲突时可用 id 精确指定。

进程生命周期与状态机

一个被管理进程大致经历:launching → online → stopping/stopped → (重启) → … → errored/stopped

pm2 ls 状态列常见取值(完整取值以 pm2 ls 实际输出与版本为准):

状态含义常见原因/对应动作
online正常运行中健康状态
launching正在启动/拉起中刚 start、restart 后的瞬间
stopping正在被停止收到 stop/restart 指令,等待进程退出
stopped已停止(记录保留)你执行了 pm2 stop
errored启动失败/运行中异常退出且重启策略认为不该再拉起代码抛错、端口被占、启动超时
waiting restart按策略等待下一次重启见重启策略(监控与告警
one-launch-status一次性任务(exec_mode 一次性脚本)结束--no-autorestart 或脚本执行完

关键机制:重启计数(restarts)

  • 每当进程退出,daemon 会记一次 restarts(表格中的列)。重启不是"玄学",是策略驱动:
    • 默认 autorestart: true —— 异常退出就重启;
    • 重启过快会被判定为 unstable(不稳定),受 max_restarts/min_uptime 约束(详见 监控与告警 的重启策略小节)。
  • 表格里的 uptime(已运行时长)、cpumemoryuser 都是 daemon 实时统计的。

崩溃自动重启:PM2 到底"看"什么

PM2 判定进程状态的依据是 进程是否还活着(OS 层面的 PID/退出码),它 不关心你的业务是否正常

  • 进程 exit(无论异常退出还是 process.exit())→ 触发重启逻辑;
  • 进程活着但"卡死"(死循环不响应请求)→ PM2 默认 不会 重启它,因为这超出进程管理器的职责(这是健康检查/监控要做的事,见 监控与告警);
  • 你可以主动给出"我已就绪/我要退出"的信号来配合 PM2 做优雅启停(见 集群模式与零停机发布 的 wait_ready 与优雅退出)。

fork 与 cluster:两种执行模式

进程模型上 PM2 提供两种 exec_mode,这是后面很多行为的根源:

模式进程形态用途
fork(默认)每个实例 = 一个独立 node app.js 进程常规应用、脚本、不需要多进程共享的应用
cluster主进程 fork 出 N 个 worker,共享一个端口,由 PM2 做负载分发吃满多核、需要零停机 reload

集群的内部细节(负载均衡、worker 通信、粘性会话等)在 集群模式与零停机发布 单独展开。此处只需记住:单实例用 fork,多核部署用 cluster

数据持久化:save / dump / resurrect

daemon 活在内存里,但它可以把"当前管理了哪些进程、用什么参数"固化下来:

命令含义
pm2 save把当前进程清单写入 ~/.pm2/dump.pm2(含启动参数、环境变量、日志路径)
pm2 resurrectdump.pm2 把进程重新拉起
pm2 startup让系统在开机时自动"启动 daemon + resurrect"(Linux 下生成 systemd 单元,见 开机自启与远程部署

一句话:pm2 本身不"记住"任何东西,除非你 pm2 save 这也是"机器重启后服务没回来"的头号原因——没 save,或 save 之后又改过进程清单没再 save。

常用速记(本页核心结论)

  1. 进程是 daemon 的子进程,由 daemon 看护,不是由你的终端看护。
  2. daemon 按用户隔离,数据落在 ~/.pm2(PM2_HOME)。
  3. 崩了会重启;重启太频繁会触发保护策略;"活着但卡死"PM2 不管。
  4. 忘了 pm2 save,重启机器 = 服务全没了。
  5. 应用日志在 ~/.pm2/logs/,PM2 自己的日志在 ~/.pm2/pm2.log,别混。

参考链接