PM2是Node.js应用最常用的进程管理工具相信很多做Node.js开发和运维的朋友都用过PM2的基本功能,比如启动应用查看状态重启停止等等,但是PM2其实有很多强大的进阶功能很多人可能都不知道,或者没有充分利用。

我在实际工作中用PM2管理了很多Node.js应用踩了很多坑也总结了很多实用的进阶技巧今天想分享一下这些PM2进阶技巧包括集群模式日志管理配置文件环境变量监控部署等等希望能帮大家更好地使用PM2管理Node.js应用提升运维效率。

一、PM2简介

先简单介绍一下PM2方便不太熟悉的朋友理解PM2(Process Manager 2)是一个开源的Node.js进程管理工具由Keymetrics公司开发主要用于管理和,守护Node.js应用它能让Node.js应用在后台运行崩溃自动重启开机自启动负载均衡日志管理等等是Node.js应用生产环境部署的标准工具之一。

PM2的基本功能大家应该都比较熟悉了,比如:

  • pm2 start app.js:启动应用
  • pm2 list:查看所有应用状态
  • pm2 restart app:重启应用
  • pm2 stop app:停止应用
  • pm2 delete app:删除应用
  • pm2 logs:查看日志
  • pm2 monit:监控面板

这些基本功能能满足大部分简单场景的需求,但是在实际生产环境中,还有很多进阶功能能让PM2用得更好更高效下面就详细说说这些进阶技巧。

二、集群模式:充分利用多核CPU

第一个重要的进阶功能是集群模式(Cluster Mode)Node.js是单线程的默认只能利用一个CPU核心而现在的服务器一般都是多核CPU只用一个核心太浪费了PM2的集群模式能启动多个应用实例利用Node.js的cluster模块实现负载均衡充分利用多核CPU提升应用的并发处理能力。

使用方法

启动应用的时候,加上-i参数指定实例数量,比如:

# 启动4个实例
pm2 start app.js -i 4

# 启动和CPU核心数相同的实例(推荐)
pm2 start app.js -i max

-i max会自动根据CPU核心数启动对应数量的实例一般推荐用这个能充分利用所有,CPU核心不用自己数核心数。

集群模式的好处

  1. 充分利用多核CPU:多个实例并行处理请求吞吐量大大提升
  2. 负载均衡:PM2自动在多个实例间分配请求不会出现某个实例过载
  3. 零停机重启:重启的时候PM2会逐个重启实例不会,同时停掉所有实例保证服务不中断
  4. 更高的可用性:某个实例崩溃了PM2会自动重启它其他实例继续服务不会影响整体可用性

注意事项

  1. 状态共享问题:集群模式下多个实例是独立的进程内存不共享,如果应用里有用内存存session、缓存等需要注意可能会出现状态不一致建议用Redis等外部存储来共享状态
  2. 实例数不是越多越好:一般实例数等于CPU核心数就够了太多实例反而会,因为上下文切换降低性能
  3. WebSocket等长连接:集群模式下WebSocket需要配置sticky session否则可能会有问题PM2也支持需要额外配置

三、配置文件:管理复杂应用的最佳实践

第二个进阶技巧是使用配置文件(Ecosystem File)而不是每次都用命令行参数启动应用当应用多了,或者配置复杂了命令行参数会很长很难管理也容易出错用配置文件能把所有应用的配置都写在一个文件里统一管理方便维护也方便版本控制。

生成配置文件

PM2提供了命令生成配置文件模板:

pm2 init

这会在当前目录生成一个ecosystem.config.js文件里面有,基本的配置模板你可以根据自己的需求修改。

配置文件示例

module.exports = {
  apps: [
    {
      name: 'web-app',
      script: './app.js',
      instances: 'max',
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3000
      },
      env_development: {
        NODE_ENV: 'development',
        PORT: 3001
      },
      max_memory_restart: '500M',
      error_file: './logs/web-app-error.log',
      out_file: './logs/web-app-out.log',
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      merge_logs: true,
      autorestart: true,
      watch: false,
      ignore_watch: ['node_modules', 'logs'],
      cron_restart: '0 3 * * *',
      restart_delay: 3000
    },
    {
      name: 'api-server',
      script: './api/server.js',
      instances: 2,
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 4000
      },
      max_memory_restart: '300M'
    }
  ]
};

使用配置文件

# 启动配置文件里的所有应用
pm2 start ecosystem.config.js

# 只启动配置文件里的某个应用
pm2 start ecosystem.config.js --only web-app

# 用指定的环境变量启动
pm2 start ecosystem.config.js --env development

# 重启配置文件里的所有应用
pm2 restart ecosystem.config.js

# 重新加载配置文件(零停机)
pm2 reload ecosystem.config.js

# 删除配置文件里的所有应用
pm2 delete ecosystem.config.js

配置文件的好处

  1. 统一管理:所有应用的配置都在一个文件里方便查看和修改
  2. 版本控制:配置文件可以提交到Git和,代码一起版本管理方便追溯和回滚
  3. 环境分离:可以配置不同环境的变量(生产、开发、测试等)切换方便
  4. 减少出错:不用每次都敲很长的命令行参数减少人为错误
  5. 可复制:配置文件可以复制到其他服务器快速部署保证环境一致

强烈建议生产环境都用配置文件来管理PM2应用不要用命令行参数临时启动不好管理也容易出问题。

四、日志管理:让日志更清晰更有用

第三个进阶技巧是日志管理PM2默认会把应用的stdout和stderr输出到日志文件,但是默认的日志配置比较简单在生产环境中需要更完善的日志管理才能方便排查问题和监控。

常用日志配置

在配置文件里可以配置以下日志相关的选项:

{
  name: 'app',
  script: 'app.js',
  // 错误日志文件路径
  error_file: './logs/app-error.log',
  // 标准输出日志文件路径
  out_file: './logs/app-out.log',
  // 日志时间格式
  log_date_format: 'YYYY-MM-DD HH:mm:ss',
  // 集群模式下合并所有实例的日志到一个文件
  merge_logs: true,
  // 日志类型:json格式方便日志分析工具处理
  log_type: 'json',
  // 禁用日志(不推荐除非特殊情况)
  // disable_logs: true
}

日志查看技巧

# 查看所有应用的实时日志
pm2 logs

# 查看指定应用的日志
pm2 logs app-name

# 只查看最后100行日志
pm2 logs app-name --lines 100

# 只查看错误日志
pm2 logs app-name --err

# 只查看标准输出日志
pm2 logs app-name --out

# 用JSON格式查看日志
pm2 logs app-name --json

# 查看日志而不跟踪(只看历史不实时更新)
pm2 logs app-name --nostream

日志切割和轮转

PM2默认不会自动切割日志日志文件会越来越大占用磁盘空间生产环境需要配置日志轮转有两种方式:

  1. 用PM2的logrotate模块
# 安装pm2-logrotate模块
pm2 install pm2-logrotate

# 配置日志轮转
pm2 set pm2-logrotate:max_size 100M  # 单个日志文件最大100M
pm2 set pm2-logrotate:retain 30       # 保留30个日志文件
pm2 set pm2-logrotate:compress true    # 压缩旧日志
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'  # 每天凌晨轮转
  1. 用系统的logrotate

Linux系统自带logrotate也可以用来轮转PM2的日志配置/etc/logrotate.d/pm2文件即可这种方式更通用也更稳定推荐生产环境用系统logrotate。

日志最佳实践

  1. 日志要带时间戳:配置logdateformat方便排查问题时定位时间
  2. 集群模式要合并日志:配置merge_logs: true否则每个实例一个日志文件不方便查看
  3. 错误日志和标准输出分开:方便单独查看错误快速定位问题
  4. 配置日志轮转:避免日志文件无限增大占满磁盘
  5. 重要日志要集中收集:如果服务器多建议用ELK、Loki等工具集中收集日志方便统一查询和分析

五、环境变量管理:不同环境灵活切换

第四个进阶技巧是环境变量管理Node.js应用通常用环境变量来区分不同环境(开发、测试、生产)和,配置敏感信息(数据库密码、API密钥等)PM2提供了灵活的环境变量管理功能。

在配置文件中定义环境变量

module.exports = {
  apps: [{
    name: 'app',
    script: 'app.js',
    // 默认环境变量(生产环境)
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
      DB_HOST: 'localhost',
      DB_PORT: 3306
    },
    // 开发环境变量
    env_development: {
      NODE_ENV: 'development',
      PORT: 3001,
      DB_HOST: 'dev-db.example.com'
    },
    // 测试环境变量
    env_test: {
      NODE_ENV: 'test',
      PORT: 3002,
      DB_HOST: 'test-db.example.com'
    }
  }]
};

切换环境

# 用默认环境(env里的配置生产环境)启动
pm2 start ecosystem.config.js

# 用开发环境启动
pm2 start ecosystem.config.js --env development

# 用测试环境启动
pm2 start ecosystem.config.js --env test

# 重启时切换环境
pm2 restart ecosystem.config.js --env development

注意:环境变量,只有在启动的时候,才会生效修改环境变量后需要重启应用才能生效,而且pm2 restart不会重新读取配置文件里的环境变量需要用pm2 reload或者先pm2 deletepm2 start或者用--update-env参数:

# 重启并更新环境变量
pm2 restart app --update-env

敏感信息处理

对于数据库密码、API密钥等敏感信息不建议直接写在配置文件里(因为配置文件通常会提交到Git会泄露)建议用以下方式:

  1. 用系统环境变量:在服务器上设置环境变量PM2会自动继承
  2. 用.env文件:用dotenv模块加载.env文件.env文件不要提交到Git
  3. 用密钥管理服务:比如HashiCorp Vault、AWS Secrets Manager等更安全

六、内存管理和自动重启

第五个进阶技巧是内存管理和自动重启Node.js应用有时候会出现内存泄漏的问题内存占用越来越大最后导致应用变慢甚至崩溃PM2提供了内存限制和,自动重启的功能能在内存超过阈值时自动重启应用避免内存泄漏导致服务不可用。

配置内存限制

{
  name: 'app',
  script: 'app.js',
  // 内存超过500M自动重启
  max_memory_restart: '500M',
  // 也可以用数字单位是字节
  // max_memory_restart: 500 * 1024 * 1024,
}

也可以命令行启动时指定:

pm2 start app.js --max-memory-restart 500M

其他重启相关配置

{
  name: 'app',
  script: 'app.js',
  // 应用崩溃后自动重启(默认true)
  autorestart: true,
  // 重启延迟单位毫秒避免频繁重启
  restart_delay: 3000,
  // 最小 uptime应用启动后多久内崩溃才算异常崩溃
  min_uptime: '10s',
  // 最大重启次数超过这个次数就不再重启(避免死循环)
  max_restarts: 10,
  // 定时重启cron表达式每天凌晨3点重启
  cron_restart: '0 3 * * *',
  // 监听文件变化自动重启(开发环境用生产环境不要开)
  watch: false,
  // 忽略监听的目录
  ignore_watch: ['node_modules', 'logs', '.git'],
}

内存监控

# 查看所有应用的内存和CPU使用情况
pm2 list

# 实时监控面板能看到内存、CPU、重启次数等
pm2 monit

# 查看某个应用的详细信息
pm2 show app-name

# 查看应用的资源使用历史(需要keymetrics)
pm2 describe app-name

最佳实践

  1. 生产环境一定要配置maxmemoryrestart:防止内存泄漏导致服务不可用阈值根据应用情况设置一般200M-1G不等
  2. 配置restart_delay:避免应用崩溃后频繁重启给系统一点喘息时间
  3. 配置max_restarts:避免应用死循环重启超过次数就停掉方便排查问题
  4. 生产环境不要开watch:watch是开发环境用的生产环境开watch会有性能问题也可能导致意外重启
  5. 定期监控内存使用:用pm2 monit或者,监控工具及时发现内存异常

七、零停机部署:reload和gracefulReload

第六个进阶技巧是零停机部署生产环境更新应用的时候,我们不希望服务中断影响用户PM2提供了零停机重启的功能能在不中断服务的情况下更新应用。

reload命令

# 零停机重启应用(集群模式下)
pm2 reload app-name

# 零停机重启配置文件里的所有应用
pm2 reload ecosystem.config.js

reload会逐个重启集群里的实例先启动一个新实例等新实例就绪后再停掉一个旧实例这样始终有实例在服务不会中断服务。

gracefulReload

pm2 gracefulReload app-name

gracefulReloadreload类似,但是会给应用发送一个shutdown消息让应用有机会优雅地关闭(比如完成当前请求关闭数据库连接等)然后再重启更优雅不会中断正在处理的请求。

应用中处理优雅关闭

要让gracefulReload生效需要在应用代码里处理SIGINT和,SIGTERM信号做清理工作:

process.on('SIGINT', () => {
  console.log('收到SIGINT信号准备关闭...');
  // 停止接受新请求
  server.close(() => {
    console.log('HTTP服务器已关闭');
    // 关闭数据库连接等
    db.close(() => {
      console.log('数据库连接已关闭');
      process.exit(0);
    });
  });
  // 超时强制退出
  setTimeout(() => {
    process.exit(1);
  }, 10000);
});

部署最佳实践

  1. 生产环境更新用reload或gracefulReload不要用restart:restart会,同时停掉所有实例导致服务中断
  2. 集群模式才能零停机:单实例模式下reload也会有短暂中断建议生产环境用集群模式
  3. 应用要处理优雅关闭:配合gracefulReload确保正在处理的请求不被中断
  4. 部署前先测试:更新代码后先在测试环境验证没问题再部署到生产
  5. 保留回滚能力:部署前备份旧版本出问题能快速回滚

八、开机自启动:服务器重启后自动恢复

第七个进阶技巧是开机自启动服务器有时候会重启(比如系统更新安全补丁等)如果PM2管理的应用不能自动启动服务器重启后服务就会中断需要人工手动启动很麻烦PM2提供了开机自启动的功能能让服务器重启后自动启动PM2和所有应用。

配置开机自启动

# 生成开机自启动脚本(会自动检测系统类型)
pm2 startup

# 按照提示执行输出的命令(一般是sudo开头的命令)
# 比如Ubuntu/Debian:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u username --hp /home/username

# 保存当前PM2的应用列表
pm2 save

这样服务器重启后PM2会自动启动,并且恢复之前pm2 save时的所有应用状态。

常用命令

# 保存当前应用列表
pm2 save

# 查看保存的应用列表
pm2 resurrect

# 禁用开机自启动
pm2 unstartup systemd

# 更新开机自启动脚本(PM2更新后需要)
pm2 startup

注意事项

  1. 修改应用后要重新pm2 save:添加、删除、修改应用后要执行pm2 save否则重启后不会恢复最新状态
  2. 用正确的用户配置:startup命令要指定正确的用户不要用root运行PM2(安全考虑)
  3. 不同系统命令不同:Linux有systemd、upstart、sysvinit等Mac有,launchdWindows有pm2-installerPM2会自动检测按照提示操作即可
  4. 验证开机自启动:配置完后可以重启服务器测试一下确保应用能自动恢复

九、PM2监控和Keymetrics

第八个进阶技巧是监控PM2自带了一些监控功能,还有官方的Keymetrics服务能提供更强大的监控和管理功能。

自带监控功能

# 实时监控面板显示CPU、内存、重启次数、日志等
pm2 monit

# 查看所有应用状态
pm2 list

# 查看某个应用的详细信息
pm2 show app-name

# 查看应用的版本信息
pm2 version

# 查看PM2的进程信息
pm2 jlist  # JSON格式
pm2 prettylist  # 格式化输出

pm2 monit是一个很实用的命令行监控面板能实时看到每个应用的CPU内存使用重启次数以及,实时日志不用装额外的工具就能快速了解应用状态很方便。

Keymetrics

Keymetrics是PM2官方的在线监控和管理平台提供了更强大的功能:

  • 实时监控CPU、内存、响应时间、错误率等指标
  • 异常告警应用崩溃、内存超阈值等会发邮件/通知
  • 日志集中管理和查询
  • 远程部署和管理多台服务器
  • 性能分析和诊断

Keymetrics有免费版和付费版免费版支持最多4个进程基本监控功能对于小项目够用了付费版支持更多进程和高级功能适合中大型项目。

接入Keymetrics

# 登录Keymetrics(需要先注册账号)
pm2 link <secret_key> <public_key>

# 查看连接状态
pm2 link list

接入后就能在Keymetrics的网页上看到所有应用的监控数据了很方便。

其他监控方案

如果不想用Keymetrics也可以用其他监控方案:

  • Prometheus + Grafana:用pm2-prometheus-exporter导出指标用Prometheus采集Grafana展示
  • ELK/EFK:集中收集和分析日志
  • Zabbix/Nagios:传统监控工具也能监控PM2应用
  • 自定义脚本:用pm2 jlist获取JSON数据自己写脚本解析和,告警

十、其他实用技巧

最后再分享一些零散的实用技巧。

技巧1:用pm2 deploy部署代码

PM2内置了部署功能能通过SSH把代码部署到远程服务器配置ecosystem.config.js里的deploy部分:

module.exports = {
  apps: [{ name: 'app', script: 'app.js' }],
  deploy: {
    production: {
      user: 'deploy',
      host: ['server1.example.com', 'server2.example.com'],
      ref: 'origin/master',
      repo: 'git@github.com:user/repo.git',
      path: '/var/www/app',
      'post-deploy': 'npm install && pm2 reload ecosystem.config.js --env production'
    }
  }
};

然后部署:

# 首次部署
pm2 deploy production setup

# 部署更新
pm2 deploy production update

# 回滚
pm2 deploy production revert 1

这个功能对于简单的部署场景很方便不用额外装Jenkins等CI/CD工具,当然复杂的部署流程还是建议用专业的CI/CD工具。

技巧2:pm2 api编程式管理

PM2提供了API可以在Node.js代码里编程式地管理PM2应用:

const pm2 = require('pm2');

// 连接PM2
pm2.connect((err) => {
  if (err) throw err;
  
  // 启动应用
  pm2.start({ script: 'app.js', name: 'my-app' }, (err, apps) => {
    // 列出所有应用
    pm2.list((err, list) => {
      console.log(list);
      pm2.disconnect();
    });
  });
});

可以用这个API写自定义的管理脚本,或者集成到自己的运维平台里。

技巧3:更新PM2本身

# 更新PM2到最新版
npm install pm2 -g

# 更新PM2后需要更新内存中的PM2守护进程
pm2 update

# 查看PM2版本
pm2 -v

注意更新PM2后一定要执行pm2 update否则内存中的PM2守护进程还是,旧版本可能会有兼容性问题。

技巧4:排查问题常用命令

# 应用启动失败查看详细错误
pm2 show app-name
pm2 logs app-name --err --lines 100

# 查看PM2自身的日志(PM2守护进程的日志)
pm2 log

# 杀掉PM2守护进程(会停掉所有应用)
pm2 kill

# 清理PM2的缓存和日志
pm2 flush  # 清空所有日志

技巧5:性能调优建议

  1. 用集群模式:充分利用多核CPU提升并发能力
  2. 配置maxmemoryrestart:防止内存泄漏
  3. 用reload更新:零停机不影响用户
  4. 配置日志轮转:避免日志占满磁盘
  5. 开启gzip压缩和静态文件缓存:如果是Web应用在Nginx层做减轻Node.js压力
  6. 用Nginx做反向代理和负载均衡:生产环境建议用Nginx在前面做反向代理处理静态文件、gzip、SSL等Node.js只处理动态请求

十一、写在最后

以上就是我总结的PM2进程管理进阶技巧包括集群模式配置文件日志管理环境变量内存管理零停机部署开机自启动监控以及,其他实用技巧希望能帮大家更好地使用PM2管理Node.js应用提升运维效率。

PM2是一个非常强大的Node.js进程管理工具很多人只用了它的基本功能其实它的进阶功能能大大提升生产环境的稳定性和,运维效率建议大家多了解和使用这些进阶功能让PM2发挥最大的价值。

当然PM2也不是万能的对于特别复杂的场景,比如大规模集群容器化部署等可能需要用KubernetesDocker Swarm等更专业的容器编排工具,但是对于大部分中小规模的Node.js应用PM2完全够用了,而且简单易用学习成本低是Node.js应用部署的好选择。

最后用一句话结束这篇文章:"PM2不只是启动应用的工具更是Node.js生产环境运维的利器用好进阶功能能让你的应用更稳定更高效运维更轻松。"

愿大家都能用好PM2管理好自己的Node.js应用服务稳定运行无忧。