PM2 入门指南

1. PM2 是什么?

PM2 = Process Manager 2

ADVANCED, PRODUCTION PROCESS MANAGER FOR NODE.JS

PM2 is a daemon process manager that will help you manage and keep your application online 24/7

上面是官网给出的 title,简单来说:它是在后台运行的 Node.js 进程管理器,提供一套针对生产环境运行时的工具集,可以保障你的程序 7 * 24 小时在线。

官网:https://pm2.keymetrics.io

文档:https://pm2.keymetrics.io/docs/usage/quick-start

总结其主要特性如下:

  • 日志管理:应用程序日志保存在服务器的硬盘中 ~/.pm2/logs/
  • 负载均衡:使用 Node cluster 集群模块,可以通过创建共享同一服务器端口的多个子进程来扩展您的应用程序。这样做还允许您以零秒停机时间重新启动应用程序,实现热重载。
  • 终端监控:可以在终端中监控您的应用程序运行状况,包括CPU使用率,使用的内存,请求/分钟等。
  • 自动停止不稳定的进程(避免无限循环)
  • 支持静态服务器功能
  • 提供 HTTP API

2. 安装

1
2
3
4
$ npm install pm2 -g

# 或
$ yarn global add pm2

可以使用工具 nvm 安装管理 Node.jsnpm ,参见我的另一篇文章:借助 nvm 安装、管理多个 NodeJS 版本

检查是否安装成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ pm2 --version

-------------

__/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____
_\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___
_\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__
_\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___
_\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____
_\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________
_\/\\\_____________\/\\\_____________\/\\\___/\\\/___________
_\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_
_\///______________\///______________\///__\///////////////__


Runtime Edition

PM2 is a Production Process Manager for Node.js applications
with a built-in Load Balancer.

Start and Daemonize any application:
$ pm2 start app.js

Load Balance 4 instances of api.js:
$ pm2 start api.js -i 4

Monitor in production:
$ pm2 monitor

Make pm2 auto-boot at server restart:
$ pm2 startup

To go further checkout:
http://pm2.io/


-------------

[PM2] Spawning PM2 daemon with pm2_home=/Users/sunqiang/.pm2
[PM2] PM2 Successfully daemonized
4.4.0

3. 基本使用

3.1. 启动

1
2
3
4
5
6
7
8
9
10
11
12
# 以指定的 Node server 入口文件启动应用
$ pm2 start app.js
[PM2] Starting /Users/sunqiang/mydev/NodeProjects/demo/demo-koa2/app.js in fork_mode (1 instance)
[PM2] Done.
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ app │ default │ 0.1.0 │ fork │ 28381 │ 0s │ 0 │ online │ 0% │ 11.9mb │ sunqiang │ disabled │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

# 启动时,指定应用名
$ pm2 start app.js --name demo

其它可用选项:

  • --watch 以监听模式启动,当文件发生变化时自动重启
  • --max-memory-restart <200MB> 设置应用重载占用的最大内存
  • --log <log_path> 指定日志文件
  • -- arg1 arg2 arg3 给启动脚本传递额外的参数
  • --restart-delay <delay in ms> 延时 x 毫秒自动重启
  • --time 日志里添加时间前缀
  • --no-autorestart 不自动重启
  • --cron <cron_pattern> 按指定的定时任务规则强制重启
  • --no-daemon 以非守护进程模式启动

3.2. 查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查看所有已启动应用的基本信息
# 同 pm2 ls 或 pm2 status
$ pm2 list

# 查看所有应用的日志(历史 + 实时)
$ pm2 logs
$ pm2 logs www # 只查看应用 www 的日志
$ pm2 logs --lines 10 # 查看最后10条历史,默认 15 条
$ pm2 logs --timestamp # 实时日志添加时间前缀
$ pm2 logs www --lines 10 --err # 只查看应用 www 的最新 10 条错误日志
$ pm2 flush # ❗️清空所有日志文件

# 查看进程详情
$ pm2 show app_name|app_id

# 查看每个应用的CPU和内存资源实时占用情况
$ pm2 monit

# 在线的 Web 诊断系统,跨服务器
# 需要注册登录或使用 Github、Google 账户授权登录
$ pm2 monitor

3.3. 管理应用状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 重启 ❗️
# 同时杀死并重启所有进程,短时间内服务不可用。
# 生成环境推荐使用 reload
$ pm2 restart app_id|app_name|all

# 重载 👍
# 始终保持一个进程在线,避免宕机
$ pm2 reload app_id|app_name|all

# 停止
$ pm2 stop app_id|app_name|all

# 关闭并删除
$ pm2 delete app_id|app_name|all

# 直接杀死 pm2 守护进程
$ pm2 kill

3.4. 静态服务器

1
2
# 将目录 dist 作为静态服务器根目录,端口为 3333
$ pm2 serve ./dist 3333

3.5. 集群模式(自动负载均衡)

1
2
3
# max 表示 PM2 将自动检测可用 CPU 的数量并运行尽可能多的进程
# max 可以自定义,如果是 4 核 CPU,设置为 2 则只占用 2 核
pm2 start app.js -i max

3.6. 开机自启动

1
2
$ pm2 startup
$ pm2 unstartup

3.7. 应用列表

1
2
3
4
5
6
7
8
# 保存当前应用列表,以后可以恢复
$ pm2 save # 同 pm2 dump

# 重新加载之前保存的应用列表
$ pm2 resurrect

# 清除保存的应用列表
$ pm2 cleardump

4. 配置文件

生成示例配置文件

1
$ pm2 ecosystem # 或 pm2 init

示例配置如下(根据实际项目需要添加、删除配置项)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
module.exports = {
apps : [{
name : 'demo', // 应用名
script : 'app.js', // 应用文件位置
env: {
PM2_SERVE_PATH: ".", // 静态服务路径
PM2_SERVE_PORT: 8080, // 静态服务器访问端口
NODE_ENV: 'development' // 设置开发环境运行时
},
env_production : {
NODE_ENV: 'production' // 设置生产环境运行时
},
instances: "max", // 将应用程序分布在所有CPU核心上,可以是整数或负数
watch: true, // 监听模式
output: './out.log', // 指定日志标准输出文件及位置
error: './error.log', // 错误输出日志文件及位置
merge_logs: true, // 集群情况下,可以合并日志
log_type: "json", // 日志类型
log_date_format: "DD-MM-YYYY", // 日志的日期格式
}],
deploy : {
production : {
user : 'SSH_USERNAME',
host : 'SSH_HOSTMACHINE',
ref : 'origin/master',
repo : 'GIT_REPOSITORY',
path : 'DESTINATION_PATH',
'pre-deploy-local': '',
'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production',
'pre-setup': ''
}
}
}

以配置文件启动示例

1
$ pm2 start ecosystem.config.js --env production

⚠️ 注意:配置文件支持 js 和 yaml 格式,还有一些没有列举的参数项,详见官方文档:https://pm2.keymetrics.io/docs/usage/application-declaration

5. 其他

5.1. 升级 PM2

1
2
3
4
5
6
7
8
9
10
11
# 更新前推荐先保存当前应用列表,方便更新后直接恢复
$ pm2 save

# 更新主程序
$ npm install pm2 -g

# 紧接着更新内存中的程序
$ pm2 update

# 恢复应用列表
$ pm2 resurrect

5.2. 日志切割

安装 pm2-logrotate-ext 扩展模块

项目地址:https://github.com/Lujo5/pm2-logrotate-ext

1
$ pm2 install pm2-logrotate-ext

重新启动应用后,pm2-logrotate-ext 以模块的形式被加载、启动。

可以通过以下命令对其配置进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 当文件大小超过此设置则执行切割
$ pm2 set pm2-logrotate-ext:max_size 1M

# 保留最新的几个日志文件
$ pm2 set pm2-logrotate-ext:retain 30

# 是否开启 gzip 压缩
$ pm2 set pm2-logrotate-ext:compress false

# 文件名的日期部分格式
$ pm2 set pm2-logrotate-ext:dateFormat YYYY-MM-DD_HH-mm-ss

# 几秒钟检查一次日志文件大小
$ pm2 set pm2-logrotate-ext:workerInterval 30

# 类似于系统的定时任务,当满足指定规则时,
# 不管日志文件大小是否达到设置的最大值,直接对日志文件进行切割
$ pm2 set pm2-logrotate-ext:rotateInterval 0 0 * * *

# 对 pm2 模块产生的日志同样进行切割处理
$ pm2 set pm2-logrotate-ext:rotateModule true

# 是否按定时任务设置规则强制执行
# 如果设置为否,则只有当日志文件大小超过设置时才进行切割
$ pm2 set pm2-logrotate-ext:forced true