Skip to content

故障排查与最佳实践

定位:生产救火手册 + 收尾清单 + 术语表。日常踩坑优先翻这里。
建议前置:核心概念、监控与告警、集群模式与零停机发布、开机自启与远程部署。

排查方法论(先建立流程,再谈个例)

遇到"服务不对",按下面的顺序查,90% 的问题能定位:

1. 状态先看全      pm2 ls                —— status / ↺ / cpu / memory 一眼扫过
2. 单进程详情      pm2 describe <id|name> —— 启动命令、日志路径、环境、重启原因相关字段
3. 应用日志        pm2 logs <name> --err  —— 是不是代码自己抛错/崩了
4. PM2 自己的日志   tail ~/.pm2/pm2.log    —— 是不是 PM2 层面的问题(如 daemon 异常)
5. 手工复现        pm2 stop <name>; node app.js —— 前台跑一次,错误立刻现形
6. 环境核对        代码依赖的端口/数据库/环境变量是否还在

黄金法则:分清"是你的代码挂了,还是 PM2 没把它管好"。PM2 只负责进程死活与资源统计,errored 的根因九成在应用侧。

高频故障速查(症状 → 原因 → 处置)

启动就 errored / 反复重启

症状可能原因处置
启动即 errored代码启动阶段抛异常前台 node app.js 复现,看报错
端口被占 EADDRINUSE旧进程没退干净/别的服务占着lsof -i :3000 找到占用者;确认是否重复 start 了同一应用
SyntaxError代码语法/依赖问题前台复现
启动很慢被判定失败启动超时/daemon 认为进程没起来wait_ready/listen_timeout 说明就绪时间(集群模式与零停机发布);调大超时
反复重启但每次能活一会运行期崩溃(未捕获异常、OOM 被杀)--err 日志与系统 dmesg/journalctl(OOM killer);配合内存保护
重启次数疯涨后停在 errored触发了重启保护策略监控与告警 重启策略:max_restartsmin_uptimerestart_delay

先做pm2 describe <name>statusrestarts、日志路径;再 pm2 logs <name> --err --lines 200

环境变量"丢了"

场景:你在 shell 里 export FOO=1pm2 start app.js,进程里确实有 FOO;但后来改了 shell 里的值,pm2 restart app进程里还是旧值

原因:被管理进程的环境是启动那一刻从 daemon 继承/固化的pm2 restart 默认不会重新读取你当前 shell 的环境。

处置:

  • 重启时带 --update-env 强制用当前 shell 环境覆盖;
  • 更推荐:把环境写进 ecosystem 文件的 env / env_xxx,或统一用 .env 加载,别依赖手工 export(配置文件)。

日志"没输出"或找不到

  • 默认日志文件在 ~/.pm2/logs/,命名形如 <name>-out-<pid>.log / <name>-error-<pid>.log(以 pm2 describe 显示的路径为准);
  • pm2 logs 没内容先确认进程真的在打印(前台复现);
  • 多实例默认各自落文件(带 pid 后缀),要合写用 merge_logs;命名细节见 日志与轮转
  • 改了 log 配置但没生效:pm2 delete 后重新 start(重启/重载不一定重建文件句柄)。

服务器重启后服务没回来

三步自查:

  1. 之前有没有 pm2 save?(没 save = 没快照,开机无从拉起)
  2. pm2 startup 生成的 systemd 命令是否真的执行了?(提示的那条 sudo env PATH=... pm2 startup systemd ... 只是打印出来,需要你手动跑)
  3. 以 root 跑过 startup,但进程是普通用户起的?→ 用户不一致,见 开机自启与远程部署

pm2 命令报错 / daemon 行为异常

  • pm2 ping 不通、命令卡住 → daemon 可能僵死:pm2 kill 杀掉旧 daemon(会顺带停掉它托管的进程),再执行 pm2 resurrect 从 dump 拉起,或直接重新 start。
  • 版本升级后建议执行 pm2 update(重启 daemon 并按 dump.pm2 恢复进程),而不是直接 pm2 resurrect
  • ~/.pm2 权限/内容损坏(如误删):备份后重建目录即可,daemon 会重新初始化;pm2 save 的快照丢失则进程清单需重建。

改完代码不生效

  • PM2 不会自动感知代码变更(除非开了 --watch,且 watch 只建议开发环境用)。
  • 发布 = 显式 pm2 reload(cluster,零停机)或 pm2 restart

集群模式下进程 errored / 连接闪断

  • 集群共享端口,若 master/某 worker 崩溃或 listen 冲突,PM2 会重建 worker;
  • 涉及粘性会话(sticky session)的应用在默认 round-robin 下会出问题,见 集群模式与零停机发布 的边界说明;
  • 查看是否因为应用不支持多进程(内存态数据、单例定时器)导致互相干扰。

日志时间不对 / 时区问题

  • PM2 的时间戳默认用系统时区;容器里常见 UTC 与本地时间不一致。
  • 需要指定格式时用日志时间戳配置(日志与轮转),或统一容器时区 TZ

生产环境最佳实践清单

进程托管

  • [ ] 用普通用户(如 www/deploy)运行,避免 root 跑 Node(安全最小权限;PM2 不提供沙箱)。
  • [ ] 不要 sudo pm2 和普通用户 pm2 混用——它们各管各的 daemon,极易"我明明 start 了却看不见"。
  • [ ] 生产用 exec_mode: cluster + instances: max(多核机器),fork 留给脚本/单例应用。
  • [ ] 给应用设置 max_memory_restart(如 512M),内存泄漏时自动重启而不是拖垮机器。
  • [ ] 应用代码处理优雅退出信号(SIGINT/SIGTERM),让 pm2 reload 真正零停机(集群模式与零停机发布)。

配置与发布

  • [ ] 把 ecosystem.config.js 纳入版本库,所有启动参数/环境都写在里面,禁止散落的 shell export。
  • [ ] 发版走 pm2 deploy 或 CI 脚本(开机自启与远程部署),不要手工 ssh + restart。
  • [ ] 首次部署完成后:pm2 save;确认 pm2 startup 的 systemd 单元已注册。
  • [ ] 每次增删/改参后重新 pm2 save

日志与监控

  • [ ] 配置日志轮转(pm2-logrotate),禁止无限增长(日志与轮转)。
  • [ ] 对关键服务做外部监控/告警(进程 down、重启次数、CPU/内存),PM2 自己不能替你报警(监控与告警)。

开发环境

  • [ ] watch 模式仅开发使用(pm2 start app.js --watch),代码变更自动重启;生产关闭。
  • [ ] 用 pm2 start ecosystem.config.js --env development 切换本地/生产环境。

术语表

术语含义
daemon / God 进程PM2 后台常驻的"监护人"进程,真正的托管者
被管理进程你交给 PM2 的应用进程(daemon 的子进程)
fork 模式每个实例一个独立进程,最简单
cluster 模式一个主进程 + N 个 worker,共享端口、可零停机 reload
online / stopped / errored进程主要状态:运行 / 已停止 / 异常(见 核心概念
restarts(↺)进程重启次数
unstablePM2 判定进程"不稳定"(频繁重启)后的保护状态
dump.pm2pm2 save 生成的进程快照文件
resurrect按快照恢复进程
reload逐个替换进程实现零停机(cluster)
gracefulReload优雅重载:先让旧进程处理完存量请求再下线(官方现口径:应用截获 SIGINT 后 reload 即优雅,见 集群模式与零停机发布
PM2_HOMEdaemon 数据目录(默认 ~/.pm2
PM2 模块pm2 install 安装的扩展(如 pm2-logrotate)
ecosystem 文件声明式配置:ecosystem.config.js(亦支持 .json / .cjs,详见 配置文件

故障自测(快速回顾)

  1. pm2 restartpm2 reload 差在哪?各在什么模式可用?
  2. 机器重启后服务丢了,前两步该检查什么?
  3. 进程内存飙到 1GB 还不停机,为什么 PM2 没管?该怎么配?
  4. shell 里改了环境变量,为什么 restart 后应用里还是旧值?
  5. 应用日志和 PM2 日志分别在哪个文件?

参考链接