pm2 使用笔记

PM 2 是什么,官网上 https://pm2.keymetrics.io/ 是说 PM2(Process Manager 2) 是 Node JS 的高级的,产品级的进程管理工具。为什么叫做 PM2,那有没有 PM 或 PM 1 呢,没有,它起步就是 2. PM2 相对于 Node JS 有点类似于 Gunicorn 和 Python Web 应用的关系。 但 PM2 比 Gunicorn 功能更强大, 其实 PM2 还能用来管理其他任何进程,不局限于 Node JS 的。

最好的入门学习教程是官方的 Quick Start。从中我们可以大概看到 PM2 的主要应用:

  1. 对进程的管理与监控
  2. 多种进程重启策略
  3. 日志的管理
  4. 使用配置文件
  5. 集群模式
  6. 用作静态 Web 服务
  7. 进行应用部署
  8. 使用环境变量

PM2 是 Node JS 应用,所以它是跨平台的。

下面来逐步体验 PM2

PM2 的安装

$ npm install pm2 -g
# 或者
$ yarn global add pm2
安装 pm2 之前需先安装好 nodejs 和 npm. pm2 安装后可用的命令有 pm2, pm2-dev, pm2-docker 和 pm2-runtime。

管理一个 Node JS 应用

先写一个简单的 app.js,内容为
 1var http = require('http');
 2var process = require('process');
 3
 4function sleep(time) {
 5    return new Promise((resolve) => setTimeout(resolve, time));
 6}
 7
 8http.createServer(function(request, response) {
 9    console.log(`received request @${new Date().toLocaleString()}`);
10    response.writeHead(200, {'Content-Type': 'text/plain'});
11    response.end('Hello World\n');
12}).listen(3000);
13
14console.log('Server running at http://127.0.0.1:3000/');
$ pm2 start app.js
看到 上图中显示了应用的 id 是 0, 名称为 app, 并且 mode 为 fork. 后面的如果使用了 -i 指定进程数目(即使指定为 1) 的话模式将变为 cluster。 其中 id 和 name, 我们可以用下面系列的命令来管理该进程了
$ pm2 stop <id|name>
$ pm2 delete <id|name>
$ pm2 start <id|name>
$ pm2 restart <id|name>
$ pm2 reload <id|name>
all 可代表所有的进程,如 pm2 stop all

pm2 启动进程时还有更丰富的参数,像

  1. --name <app_name>: 指定进程名,而不是取 app.jsapp 部分作为进程名
  2. -i --instances <number: 起动应用的实例数
  3. --watch: 当有代码文件更改时自动重启应用,这对开发时很有用
  4. --max-memory-restart <200MB>: 应用内存达到一个阈值时重启
  5. --log <log_path>: 指定 log 文件位置,默认在  ~/.pm2/logs 目录下
  6. -- arg1 arg2 arg3: 指定应用的参数
  7. --no-autorestart: 不重新启动
  8. --cron <cron_pattern>: 以 cron 表达式来指定应用的重启
  9. --no-daemon: 不进入后台模式

查看进程

我们在用 pm2 start 后会列出进程状态,以后可以随时用命令
$ pm2 [ls|list|status]
列出上面的表格。

来看下 pm2 start app.js 起动的什么进程,先用 netstat 命令找到 3000 端口号上的进程 id
$ netstat -nap |grep 3000
tcp6 0 0 :::3000 :::* LISTEN 15559/node /home/va
进程 id 是 15559, 再用 ps 列出相关的命令
1vagrant@ubuntu2004:~$ ps -ef|grep 15559 | grep -v color
2vagrant    15559   13384  0 05:11 ?        00:00:00 node /home/vagrant/app.js
3vagrant@ubuntu2004:~$ ps -ef|grep pm2 | grep -v color
4vagrant    13384       1  0 02:24 ?        00:00:08 PM2 v5.1.0: God Daemon (/home/vagrant/.pm2)

注意到的是 3000 端口号是由 node app.js 直接启动的。我们将在后面测试 pm2 进行负载均衡时启动的进程情况。

显示日志

如果我们启动应用时没有加 --no-daemon, 那么 pm2 启动的应用进入了后台模式,可查看日志可以用命令
$ pm2 logs                       显示所有应用的日志
# 或
$ pm2 logs <id|name> 显示特定 id 或 name 所指示的日志
运行 pm2 logs,并进行两次 curl http://localhost:3000/ 请求看下日志显示
$ pm2 logs
[TAILING] Tailing last 15 lines for [all] processes (change the value with --lines option)
/home/vagrant/.pm2/logs/app-error.log last 15 lines:
/home/vagrant/.pm2/logs/app-out.log last 15 lines:
0|app | Server running at http://127.0.0.1:3000/ 0|app | received request @8/12/2021, 5:23:56 AM
0|app | received request @8/12/2021, 5:23:57 AM
打开 pm2 logs 后会实时显示打印的日志。

用作静态 Web 服务

$ pm2 serve <path> <port>
默认 path 为当前目录,port 默认为 8080, 所以光运行
$ pm2 serve
# 相当于是
$ pm2 serve . 8080
这就启动了 Web 服务,主目录为当前目录,pm2 还能结合  --watch 参数在文件改动时自动重启。pm2 serve --spa 会把 index.html 作为入口。

集群模式(负载均衡)

在 pm2 start 启动应用时可用 -i <number> 来指定进程实例数目,或可为 <number>指定特殊的值

  1. 0/max: 与 CPU 数目相同
  2. -1: CPU 数目减 1

测试下面的命令
$ pm2 start -i 3 app.js
mode 为 cluster,即使用 pm2 start -i 1 app.js 指定为 1 也是 cluster 模式。

启动了三个 node js 就用,现在打开 pm2 logs, 进行多次的 curl http://localhost:3000/ 请求,看下请求分发的情形

负载均衡的策略基本上就是 round-robin

再来看下进程与端口的关系
 1vagrant@ubuntu2004:~$ netstat -nap |grep 3000
 2(Not all processes could be identified, non-owned process info
 3 will not be shown, you would have to be root to see it all.)
 4tcp6       0      0 :::3000                 :::*                    LISTEN      13384/PM2 v5.1.0: G
 5vagrant@ubuntu2004:~$ ps -ef|grep 13384 | grep -v color
 6vagrant    13384       1  0 02:24 ?        00:00:10 PM2 v5.1.0: God Daemon (/home/vagrant/.pm2)
 7vagrant    15966   13384  0 05:31 ?        00:00:00 node /home/vagrant/app.js
 8vagrant    15973   13384  0 05:31 ?        00:00:00 node /home/vagrant/app.js
 9vagrant    15984   13384  0 05:31 ?        00:00:00 node /home/vagrant/app.js
10vagrant@ubuntu2004:~$ ps -ef|grep pm2 | grep -v color
11vagrant    13384       1  0 02:24 ?        00:00:10 PM2 v5.1.0: God Daemon (/home/vagrant/.pm2)
pm2 start app.js 有点不一样了,node app.js 不再直接接收请求了,而是由  PM2 v5.1.0: God Daemon 这个进程来监听端口 3000 了,它也是三个 node app.js 进程的父进程。

进程的监控

能够对进程的实时监控可有效的保证应用的稳定性,主要有两个命令
$ pm2 monit
$ pm2 <monitor|plus>
不明白为什么要把  monit 和 monitor 搞成不一样

pm2 monit 会在本地打开一个全屏控制台窗口 PM2 Dashboard,为了进一步展示监控的效果,再用 pm2 start app1.js 多启动一个应用,于是 pm2 monit 就是下面这样子的

运行 pm2 <monitor|plus> 来监控会要求先在 app.pm2.io 上创建一个帐户,进新建一个 Bucket,然后在命令行下输入用户和密码连接到前面建立好的 Bucket。运行的机制是本地的 pm2 会启动一个 `PM2 Agent` 进程把运行状况数据上报到  app.pm2.io. 于是打开 Web 窗口就是下面这样的

这个界面好是好,看到的信息非常直观,只是大部的 PM2 Plus 的功能都要交钱。

不想继续用这个 Web 界面来监控的话,用下面命令断开链接
$ pm2 link delete

使用配置文件

pm2 命令有众多的参数,前面所做都可以用一个配置文件来描述,然后启动时只需要 pm2 start ecosystem.config.js,其他的 pm2 命令,如 stop, restart, reload, delete 等也支持配置文件。
$ pm2 init simple       # 产生一个简单的配置文件样例
# pm2 init|ecosystem  将会生成稍复杂一点的配置文件样例
比如我们前面启动的进程用配置文件 ecosystem.config.js 来描述就是
 1module.exports = {
 2  apps : [{
 3    script : "./app.js",
 4    instances: 3
 5  },{
 6    script: "./app1.js"
 7  }, {
 8    name: "static-page-server-8080",
 9    script: "serve"
10  }]
11}

接下来就只要用
$ pm2 start ecosystem.config.js
会启动相应的任务

更多的配置属性参见 https://pm2.keymetrics.io/docs/usage/application-declaration/

环境变量的设定

如果通过命令
foo=BAR pm2 start app.js
那我们在 app.js 中可用如下代码获得该环境变量
1var process = require('process');
2console.log(process.env.foo);

现在来看用配置文件如何声明环境变量,我们把 ecosystem.config.js 改为
 1module.exports = {
 2  apps : [
 3      {
 4        script: "./app.js",
 5        env: {
 6            "PORT": 3000,
 7            "NODE_ENV": "development"
 8        },
 9        env_qa: {
10            "PORT": 8080,
11            "NODE_ENV": "qa"
12        },
13        env_prod: {
14            "PORT": 80,
15            "NODE_ENV": "production",
16        }
17      }
18  ]
19}

app.js 中把 listen() 调用代码改为
1.listen(process.env.PORT)

那么可以尝试如下的命令
$ pm2 start ecosystem.config.js                              # 默认时监听端口为 3000
$ pm2 restart ecosystem.config.js --env qa          # 选择  qa 环境变量,即 env_qa 对应的声明,监听端口变为 8080
$ pm2 restart ecosystem.config.js --env prod      # 监听端口就变成为 80

其他内容

pm2-dev: 该命令给开发者用的,它相当于 pm2 启动时加了 --watch, --no-daemon 参数,并且 autorestart: true。pm2 启动时 autorestart 默认为 true, 除非使用 --no-autorestart 参数。

pm2-docker 和 pm2-runtime 是同一个东西,我查看
$ cat /usr/local/bin/pm2-docker
$ cat /usr/local/bin/pm2-runtime
看到的都是
1#!/usr/bin/env node
2
3require('../lib/binaries/Runtime4Docker.js');

但在网上却没看到什么介绍,如果在 docker 中使用 pm2, pm2-docker 是以 no-daemon 的方式运行,这样就不会被认为 pm2 执行完成而结束 docker 任务。

pm2 deploy: pm2 还支持部署到本地或 ssh 远程,还能进行版本的回滚,这里不详叙。

pm2 update: 更新 pm2 自身

pm2 startup, pm2 unstartup: 支持 pm2 开机自动运行。需事先 pm2 save 保存进程状态。

链接:

  1. pm2源码学习
  2. pm2 使用教程
  3. pm2安装与使用 (生产环境部署)
永久链接 https://yanbin.blog/pm2-notes/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。