人人都会AI编程

集群模式、负载均衡、日志管理、自动重启

更新时间:2026-07-11

上一节我们梳理了 PM2 的基本安装与常用命令,能够将 Node.js 应用作为后台守护进程运行。但在实际生产环境中,仅仅保证“进程不挂”远远不够:我们需要充分利用多核 CPU、平滑分配流量、集中管理日志,并在进程异常时自动恢复。PM2 针对这些需求提供了开箱即用的能力,而且几乎所有配置都可以通过一份 ecosystem.config.js 文件集中管理。

集群模式:一行命令榨干多核性能

Node.js 的单线程模型决定了它默认只能使用一个 CPU 核心。在多核服务器上,如果我们只启动一个 Node 进程,其他核心就会闲置。PM2 内置的集群模式本质上是对 Node.js 原生 cluster 模块的封装,它能够在启动时根据配置自动派生(fork)出多个子进程,每个子进程都独立运行在同一份代码上,共享同一个端口。

启用集群模式极为简单。假设我们的应用入口是 app.js,只需在启动命令中添加 -i 参数:

# 使用所有可用 CPU 核心
pm2 start app.js -i max

# 手动指定进程数量,例如 4 个
pm2 start app.js -i 4

-i max 会让 PM2 自动检测服务器的 CPU 核数,并为每个核心创建一个工作进程。执行后,通过 pm2 list 可以看到同一个应用的名字下方出现了多个 cluster 模式的进程,它们各自占用一个核心,共同对外提供服务。

如果需要更精细的配置,推荐使用 ecosystem.config.js 文件:

module.exports = {
  apps: [{
    name: 'my-api',
    script: './app.js',
    exec_mode: 'cluster',   // 指定为集群模式
    instances: 'max',       // 或具体数字
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }]
};

然后通过 pm2 start ecosystem.config.js 一键启动整个集群。这套配置文件可以同时管理多个应用,也可以为不同环境设置不同的环境变量,极大方便了部署流程。

集群模式的优势在于:

  • 无需修改业务代码:应用仍然监听同一个端口(如 3000),PM2 内部会自动处理多进程间的端口共享,对开发者透明。
  • 充分利用硬件资源:在 8 核服务器上启动 8 个进程,理论吞吐量可以线性增长(受业务逻辑及数据库等外部资源制约)。
  • 无缝热重载:执行 pm2 reload my-api 时,PM2 会逐个重启工作进程,保证服务在更新期间不会中断(零停机部署)。

需要注意的是,如果应用中有需要在进程间共享的内存状态(如本地缓存、WebSocket 连接映射),需要额外引入 Redis 或通过消息总线同步,因为不同工作进程的内存是完全独立的。

负载均衡:内置 Round-Robin 调度

在集群模式下,多个工作进程监听同一个端口,那么新到的请求到底由哪个进程来处理?PM2 通过内置的轮询(round-robin)负载均衡来解决这个问题。

原理如下:PM2 在启动时会创建一个主进程(Master),负责监听服务器端口。当外部请求到达时,Master 不再关心请求的内容,而是按照顺序将请求分发给池中的子进程,就像发牌一样从头到尾循环。每个子进程拿到请求后独立处理并返回响应,Master 只负责转发,不干涉具体逻辑。

对于开发者来说,这个负载均衡完全是透明的。你不需要像传统部署一样在前面架设 Nginx 来做反向代理和负载均衡,PM2 已经帮你做完了。当然,如果你的应用需要更复杂的负载策略(如基于 IP 的粘性会话、按 URL 路由),或者需要与静态资源服务器、HTTPS 终结等功能配合,那么将 PM2 放在 Nginx 后面依然是常规做法。但对于大量中小型 API 服务而言,PM2 内置的负载均衡足以应对绝大多数场景,减少了运维组件。

日志管理:集中收集、实时查看、自动切割

PM2 会自动捕获每个应用进程的标准输出(stdout)和标准错误(stderr),并将它们写入到统一的日志文件中。默认存储路径为:

  • 标准日志:~/.pm2/logs/<应用名>-out.log
  • 错误日志:~/.pm2/logs/<应用名>-error.log

你可以直接通过 PM2 命令行实时查看日志,而不必登录服务器手动 tail 文件:

# 查看所有应用的合并日志
pm2 logs

# 查看指定应用的日志
pm2 logs my-api

# 仅显示错误日志
pm2 logs --err

# 清空所有日志文件(谨慎使用)
pm2 flush

在多进程集群模式下,pm2 logs 会将所有工作进程的日志流合并输出,并自动在每行前添加进程 ID 标识(如 0|my-api | ...),便于区分来源。这对于排查线上问题极其方便。

随着运行时间的增长,日志文件会越来越大,直接写入单个大文件不仅占用磁盘,还影响读取效率。PM2 提供了一个插件 pm2-logrotate 来自动切割和归档日志:

# 安装日志轮转插件
pm2 install pm2-logrotate

# 配置(可选,安装后会有默认值)
pm2 set pm2-logrotate:max_size 10M        # 单文件最大 10MB 时切割
pm2 set pm2-logrotate:retain 30           # 保留最近 30 个归档文件
pm2 set pm2-logrotate:compress true       # 压缩旧日志
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'  # 每天凌晨切割

配置完成后,pm2-logrotate 会自动按规则处理日志文件,无需重启应用。这对于生产环境的长期运营是一项基本要求。

自动重启:从崩溃、内存溢出到系统重启的全链路守护

进程守护最核心的诉求是:当进程因为异常退出时,能够自动重新拉起。PM2 在这方面提供了三个层面的保障。

1. 异常崩溃自动重启

PM2 默认会在工作进程非正常退出时(即退出码不是 0 且不是主动关闭)立即尝试重启。你可以通过配置来控制最大重启次数,防止陷入“重启—崩溃—重启”的死循环:

// ecosystem.config.js
{
  // ...
  max_restarts: 10,           // 连续重启 10 次后放弃
  min_uptime: '10s',          // 运行不足 10 秒的视为异常
  restart_delay: 5000         // 每次重启间隔 5 秒
}

当应用连续异常重启达到 max_restarts 次后,PM2 会将该进程标记为 errored 并停止尝试,避免无休止的反复消耗资源,同时便于运维人员介入。

2. 内存阈值自动重启

Node.js 应用最常见的问题之一是内存泄漏,导致进程占用的内存持续增长,最终触发 OOM(Out of Memory)或被操作系统杀死。PM2 允许设置一个内存上限,一旦工作进程超过该值,自动重启该进程:

{
  // ...
  max_memory_restart: '500M'  // 超过 500MB 时自动重启
}

在集群模式下,PM2 会重启触发阈值的那一个进程,其他进程照常工作,整个过程对整体服务影响极小。这个特性对于线上运行不稳定的早期项目非常实用,可以在彻底定位内存泄漏之前,先保障服务可用。

3. 服务器重启后的自动恢复

当服务器因维护或其他原因需要重启时,你当然不希望手动登录再一个个启动应用。PM2 的 startup 命令会生成系统级的启动脚本(如 systemd 或 upstart),确保机器启动后 PM2 守护进程自动拉取之前保存的应用列表并全部启动:

# 生成启动脚本
pm2 startup

# 执行屏幕上输出的命令(需 root 权限)
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u your_user --hp /home/your_user

# 保存当前应用列表,下次开机时自动恢复
pm2 save

执行完上述步骤后,你可以直接重启服务器验证——应用会在系统启动后几分钟内自动上线,无需任何人工操作。

通过集群模式榨取多核性能、内置负载均衡简化流量调度、集中日志管理配合自动轮转、以及从进程崩溃到系统重启的全方位自动恢复,PM2 为 Node.js 应用提供了极为务实的一站式生产守护方案。在资源不充裕或不需要 Kubernetes 等重编排平台的场景下,仅靠 PM2 就已经能够获得可靠且高性能的线上运行能力。