监控、内存保护与重启策略
定位:回答两类问题——"现在服务健不健康"(监控) 与 "挂了之后 PM2 到底按什么规矩重启"(策略)。
一句话总纲:PM2 只管"进程死活 + 资源统计 + 按策略重启";告警与健康检查要自己搭。
读懂 pm2 ls
pm2 ls输出表格各列(5.x 起基本一致):
| 列 | 含义 | 怎么用 |
|---|---|---|
name | 应用名 | 管理入口 |
id | 进程编号 | 脚本内精确操作 |
mode | fork / cluster | 判断部署形态 |
↺(restarts) | 重启次数 | >0 就说明发生过崩溃/被杀/重启 |
status | online/stopped/errored/… | 第一眼健康度 |
cpu | 实时 CPU%(瞬时值) | 毛刺排查 |
memory | 实时内存占用 | 看是否有上涨趋势 |
uptime | 已运行时长 | 配合 ↺:刚重启过会很小 |
读表心法:status 决定"活着没";↺ 决定"稳不稳";memory 决定"要不要加保护/排查泄漏"。
深入单进程:pm2 describe
pm2 describe api它给出一个进程的"全息档案",排查必看字段:
- 身份与状态:
status、name、id、namespace - 重启历史:
restarts、unstable restarts(不稳定重启次数)、created at、exit code(上次退出的退出码) - 启动方式:
script path、script args、exec cwd、exec mode、interpreter、node args、watch、cron restart - 资源护栏:
max memory restart - 日志/文件:
out log path、error log path、pid path - 环境:
env(可确认 NODE_ENV 到底注入没)
排查"这个进程到底怎么被拉起来的"——答案全在
describe里,比猜强一百倍。
进程状态与"稳定"判定
status 常见取值见 核心概念 §5。这里补两个高频概念:
errored不等于"代码 bug 被捕获显示":它表示进程起不来(如端口占用、语法错误)或重启策略已放弃继续拉。根因去应用日志找。- unstable(不稳定):进程反复在短时间内崩溃→重启,PM2 会认为"再拉也没用",按策略停止并标记,避免无限空转烧 CPU。
内存保护:max_memory_restart
# CLI
pm2 start app.js --max-memory-restart 512M
# ecosystem
max_memory_restart: '512M'- 语义:PM2 周期性采样进程内存(官方口径:内存检查 worker 约每 30s 跑一次),超过阈值即重启该进程(计入 restart)。
- 单位写法:
512M、1G、100K;也可写纯数字(默认单位字节,不推荐,易错)。 - 典型值:Node 默认堆上限约 2GB(老版本 1.5GB)场景下,业务常设
512M–1G。 - 定位:它是"止损"护栏,不是"修泄漏"的药。若看到它频繁触发,请查应用内存泄漏(heap snapshot、
--node-args "--max-old-space-size"调优等)。
采样是"周期性的",不是纳秒级硬限制;突刺超限不一定会立刻触发。
重启策略字段全解
以下字段决定"崩了之后怎么拉、拉几次、隔多久"(ecosystem 写法,默认值以官方文档为准):
| 字段 | 含义 | 典型用法 |
|---|---|---|
autorestart | 异常退出后是否自动重启(默认 true) | 跑一次性任务设 false |
max_restarts | “不稳定重启”次数的保护上限(默认 16) | 频繁崩溃时防止无限重启 |
min_uptime | 一次“稳定运行”的最小时长:活过它才算一次稳定启动 | 启动慢的应用调大它,避免被误判不稳定 |
restart_delay | 每次重启前固定等待(ms) | 依赖下游就绪时给缓冲 |
exp_backoff_restart_delay | 指数退避重启:首间隔=设定值,逐次翻倍,封顶 15s;稳定运行 >30s 后重置 | 连崩时避免雪崩式重启 |
cron_restart | cron 定时整点重启(需进程正在运行才生效;如 '0 0 * * *') | 每天低峰清理长驻进程 |
判定“不稳定”的逻辑(官方口径):重启间隔小于 1s(或小于你设的 min_uptime)的连续重启被计为“不稳定重启”;达到 max_restarts(默认 16)后 PM2 停止自动重启、状态转 errored——这是保护机制,不是 bug。指数退避期间,进程状态会显示 waiting restart。
配置建议
- 常规服务:
autorestart:true+restart_delay: 1000~3000,避免下游未就绪时的连崩; - 依赖外部强、启动慢的服务:调大
min_uptime/ 用wait_ready(集群模式与零停机发布); - 不想在流量高峰被"反复拉死"的:
exp_backoff_restart_delay: 100+max_restarts收敛。
监控与告警怎么搭
先认清边界:PM2 只给你"看"的能力(list/monit/describe/jlist)和"策略执行"(重启)。它默认不会主动报警(没有短信/钉钉/邮件通道)。想告警,有几种路线:
路线 1:命令/API 自建巡检(零成本,自控)
PM2 提供机器可读输出,写个 cron/脚本轮询即可:
pm2 jlist # 全部进程信息 JSON(每行一条),脚本最爱
pm2 prettylist # 格式化 JSON示例思路(伪代码):
// health-check.js:每 1 分钟跑一次,异常就发告警
const procs = JSON.parse(execSync('pm2 jlist').toString());
for (const p of procs) {
if (p.pm2_env.status !== 'online') alert(`${p.name} 不在线!`);
if (p.pm2_env.restart_time > 5) alert(`${p.name} 重启次数异常`);
if (p.monit.memory > 600 * 1024 * 1024) alert(`${p.name} 内存过高`);
}用 systemd timer 或 crontab 调度,把 alert() 换成 webhook(钉钉/飞书/Slack)。
路线 2:官方托管面板 pm2.io(原 Keymetrics / PM2 Plus)
- PM2 自带了遥测/指标 agent(
@pm2/io),可接入官方托管服务app.pm2.io:web 仪表盘、历史曲线、重启告警、异常捕获等。 - 需要注册账号并在本机
pm2 link/配置(免费额度存在,商用条款以官方为准)。 - 若团队不允许数据出内网,此路线不可用,回到路线 1 或 3。
路线 3:接入既有监控体系
- Prometheus 生态:社区有把
pm2 jlist/@pm2/io指标导出到 Prometheus 的 exporter,配合 Grafana 面板; - 或者直接把进程信息打进应用自身的 metrics 端点(
/metrics),由应用暴露,与 PM2 无关但更灵活。
结论:小项目 → 路线 1 的脚本 + 日志轮转就够;大项目 → 用监控体系统一收,PM2 只管把进程和指标喂出来。
小结:让 PM2 真正"省心"的三件套
// ecosystem.config.js
{
name: 'api',
script: 'app.js',
max_memory_restart: '512M', // 1) 内存护栏
autorestart: true,
restart_delay: 2000, // 2) 崩了等 2s 再拉,别连崩
exp_backoff_restart_delay: 100,
max_restarts: 16, // 3) 连崩保护(默认 16),别无限空转
}配上外部巡检脚本(路线 1)与日志轮转(日志与轮转),一台机器的单应用托管基本就齐了。
