故障排查与最佳实践
定位:生产救火手册 + 收尾清单 + 术语表。日常踩坑优先翻这里。
建议前置:核心概念、监控与告警、集群模式与零停机发布、开机自启与远程部署。
排查方法论(先建立流程,再谈个例)
遇到"服务不对",按下面的顺序查,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_restarts、min_uptime、restart_delay |
先做:pm2 describe <name> 看 status、restarts、日志路径;再 pm2 logs <name> --err --lines 200。
环境变量"丢了"
场景:你在 shell 里 export FOO=1 后 pm2 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(重启/重载不一定重建文件句柄)。
服务器重启后服务没回来
三步自查:
- 之前有没有
pm2 save?(没 save = 没快照,开机无从拉起) pm2 startup生成的 systemd 命令是否真的执行了?(提示的那条sudo env PATH=... pm2 startup systemd ...只是打印出来,需要你手动跑)- 以 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。
日志与监控
开发环境
- [ ] 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(↺) | 进程重启次数 |
| unstable | PM2 判定进程"不稳定"(频繁重启)后的保护状态 |
| dump.pm2 | pm2 save 生成的进程快照文件 |
| resurrect | 按快照恢复进程 |
| reload | 逐个替换进程实现零停机(cluster) |
| gracefulReload | 优雅重载:先让旧进程处理完存量请求再下线(官方现口径:应用截获 SIGINT 后 reload 即优雅,见 集群模式与零停机发布) |
| PM2_HOME | daemon 数据目录(默认 ~/.pm2) |
| PM2 模块 | pm2 install 安装的扩展(如 pm2-logrotate) |
| ecosystem 文件 | 声明式配置:ecosystem.config.js(亦支持 .json / .cjs,详见 配置文件) |
故障自测(快速回顾)
pm2 restart和pm2 reload差在哪?各在什么模式可用?- 机器重启后服务丢了,前两步该检查什么?
- 进程内存飙到 1GB 还不停机,为什么 PM2 没管?该怎么配?
- shell 里改了环境变量,为什么 restart 后应用里还是旧值?
- 应用日志和 PM2 日志分别在哪个文件?
