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 的主要应用:
- 对进程的管理与监控
- 多种进程重启策略
- 日志的管理
- 使用配置文件
- 集群模式
- 用作静态 Web 服务
- 进行应用部署
- 使用环境变量
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,内容为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var http = require('http'); var process = require('process'); function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); } http.createServer(function(request, response) { console.log(`received request @${new Date().toLocaleString()}`); response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }).listen(3000); console.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 启动进程时还有更丰富的参数,像
- --name <app_name>: 指定进程名,而不是取
app.js
的app
部分作为进程名 - -i --instances <number: 起动应用的实例数
- --watch: 当有代码文件更改时自动重启应用,这对开发时很有用
- --max-memory-restart <200MB>: 应用内存达到一个阈值时重启
- --log <log_path>: 指定 log 文件位置,默认在 ~/.pm2/logs 目录下
- -- arg1 arg2 arg3: 指定应用的参数
- --no-autorestart: 不重新启动
- --cron <cron_pattern>: 以 cron 表达式来指定应用的重启
- --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 列出相关的命令
1234 vagrant@ubuntu2004:~$ ps -ef|grep 15559 | grep -v colorvagrant 15559 13384 0 05:11 ? 00:00:00 node /home/vagrant/app.jsvagrant@ubuntu2004:~$ ps -ef|grep pm2 | grep -v colorvagrant 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>指定特殊的值
- 0/max: 与 CPU 数目相同
- -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
再来看下进程与端口的关系
1234567891011 vagrant@ubuntu2004:~$ netstat -nap |grep 3000(Not all processes could be identified, non-owned process infowill not be shown, you would have to be root to see it all.)tcp6 0 0 :::3000 :::* LISTEN 13384/PM2 v5.1.0: Gvagrant@ubuntu2004:~$ ps -ef|grep 13384 | grep -v colorvagrant 13384 1 0 02:24 ? 00:00:10 PM2 v5.1.0: God Daemon (/home/vagrant/.pm2)vagrant 15966 13384 0 05:31 ? 00:00:00 node /home/vagrant/app.jsvagrant 15973 13384 0 05:31 ? 00:00:00 node /home/vagrant/app.jsvagrant 15984 13384 0 05:31 ? 00:00:00 node /home/vagrant/app.jsvagrant@ubuntu2004:~$ ps -ef|grep pm2 | grep -v colorvagrant 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 来描述就是
1 2 3 4 5 6 7 8 9 10 11 |
module.exports = { apps : [{ script : "./app.js", instances: 3 },{ script: "./app1.js" }, { name: "static-page-server-8080", script: "serve" }] } |
接下来就只要用
$ pm2 start ecosystem.config.js
会启动相应的任务
更多的配置属性参见 https://pm2.keymetrics.io/docs/usage/application-declaration/。
环境变量的设定
如果通过命令
foo=BAR pm2 start app.js
那我们在 app.js 中可用如下代码获得该环境变量
1 2 |
var process = require('process'); console.log(process.env.foo); |
现在来看用配置文件如何声明环境变量,我们把 ecosystem.config.js 改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
module.exports = { apps : [ { script: "./app.js", env: { "PORT": 3000, "NODE_ENV": "development" }, env_qa: { "PORT": 8080, "NODE_ENV": "qa" }, env_prod: { "PORT": 80, "NODE_ENV": "production", } } ] } |
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 2 3 |
#!/usr/bin/env node require('../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
保存进程状态。
链接:
本文链接 https://yanbin.blog/pm2-notes/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。