https://github.com/Unitech/pm2
当前使用场景:产品环境守护进程。
常用命令
启动项目
pm2 start xxx.js #直接启动入口文件
pm2 start xxx.json #通过配置启动
配置文件参考:
[
{
"name": "app",
"script": "babel.js",
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"cwd": "/home/project",
"error_file": "/home/project/logs/app.err.log",
"out_file": "/home/project/logs/app.out.log",
"max_memory_restart": "800M",
"instances": 0,
"exec_mode": "cluster",
"merge_logs": true,
"env": {
"NODE_ENV": "production"
}
},
{
"script": "./examples/child.js",
"error_file": "errLog.log",
"out_file": "outLog.log",
"pid_file": "child",
"instances": "4",
"min_uptime": "10",
"max_restarts": "4"
},
{
"script": "examples/env.js",
"error_file": "errEcho.log",
"out_file": "outEcho.log",
"name": "ok",
"pid_file": "echo.pid",
"max": "1",
"exec_mode": "cluster_mode",
"port": "9001",
"env_variable": "TOTO",
"TEST_VARIABLE": "YESSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSIR"
}
]
重启项目
pm2 restart #PID# #重启一个进程
pm2 restart app-name #重启一个应用
pm2 restart all #重启所有项目
停止
pm2 stop #PID#
pm2 stop app-name
终止
pm2 delete app-name #删除一个进程
pm2 kill #终止所有进程
开机自启
pm2 startup
参考官方文档获取详细使用说明。
自动重启
设置内存使用过高上限,可以通过配置文件这一项:
{
"max_memory_restart": "800M"
}
PM2
是一个很好的工具,提供了max-memory-restart
内存溢出重启的功能。
但美中不足的是,没有 CPU 限制重启的功能。
同时,也无法进行远程手动重启。但好在,PM2 提供了 JSON 格式列表输出,让我们可以自己去写一些守护进程,或者整合到已有的运维管理系统中。
pm2 jlist
结果会是这样的 json:
[
{
"pid": 28701,
"name": "xxxx",
"pm2_env": {
"name": "xxxx",
"max_memory_restart": 838860800,
"instances": 0,
"cwd": "/xxxx/project",
"merge_logs": true,
"vizion": true,
"pmx": true,
"automation": true,
"autorestart": true,
"treekill": true,
"env": {
"PM2_JSON_PROCESSING": "true",
"LSCOLORS": "Gxfxcxdxbxegedabagacad",
"LESS": "-R",
"PAGER": "less",
"SSH_TTY": "/dev/pts/1",
"SSH_CLIENT": "218.94.29.190 53115 22",
"SHELL": "/bin/bash",
"TERM": "xterm-256color",
"XDG_SESSION_ID": "814",
"NODE_ENV": "production",
"max_memory_restart": 838860800,
"instances": 0,
"merge_logs": true,
"vizion": true,
"pmx": true,
"automation": true,
"autorestart": true,
"treekill": true,
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"exec_mode": "cluster_mode",
"node_args": [],
"exec_interpreter": "node",
"pm_out_log_path": "/xxxxx/logs/fish.out.log",
"pm_err_log_path": "/xxxxx/logs/fish.err.log"
},
"log_date_format": "YYYY-MM-DD HH:mm:ss Z",
"exec_mode": "cluster_mode",
"node_args": [],
"pm_exec_path": "/xxxx/babel.js",
"pm_cwd": "/xxxxx/project",
"exec_interpreter": "node",
"pm_out_log_path": "/xxxxxx/xxx.out.log",
"pm_err_log_path": "/xxxxxx/xxx.err.log",
"NODE_APP_INSTANCE": 0,
"vizion_running": false,
"PM2_JSON_PROCESSING": "true",
"LESSCLOSE": "/usr/bin/lesspipe %s %s",
"XDG_RUNTIME_DIR": "/run/user/1000",
"LESSOPEN": "| /usr/bin/lesspipe %s",
"LC_CTYPE": "zh_CN.UTF-8",
"SSH_TTY": "/dev/pts/1",
"SHELL": "/bin/bash",
"NODE_ENV": "production",
"fish": "{}",
"status": "online",
"pm_uptime": 1472561001434,
"axm_actions": [],
"axm_monitor": {
"Loop delay": {
"value": "0.92ms",
"agg_type": "avg",
"alert": {}
}
},
"axm_options": {
"http": false,
"http_latency": 200,
"http_code": 500,
"ignore_routes": [],
"profiling": true,
"errors": true,
"alert_enabled": true,
"custom_probes": true,
"network": false,
"ports": false,
"module_conf": {},
"module_name": "fish",
"module_version": "1.1.3",
"pmx_version": "0.6.2",
"error": true
},
"axm_dynamic": {},
"created_at": 1472561000966,
"pm_id": 3,
"restart_time": 1,
"unstable_restarts": 0,
"_pm2_version": "1.1.3",
"versioning": {
"type": "git",
"update_time": "2016-09-02T07:25:14.113Z",
"comment": "v3.6.12 - fix-importer",
"unstaged": false,
"branch": "HEAD",
"remotes": ["origin"],
"remote": "origin",
"branch_exists_on_remote": true,
"ahead": false,
"next_rev": null
},
"node_version": "6.3.0",
"exit_code": 0
},
"pm_id": 3,
"monit": {
"memory": 90591232,
"cpu": 0
}
}
]
其中每一列数据都有 rows[i].monit.cpu
,值范围 0~100。可以用later
写定时脚本监控并重启。
示例代码:
import { exec } from 'child_process';
import numeral from 'numeral';
exec('pm2 jlist', (err, stdout, stderr) => {
if (stderr) {
console.log(stderr);
}
const result = stdout.split('\n');
// 如果不存在 PM2 进程,将会打初始化日志
while (result[0].indexOf('[PM2]') === 0) {
result.shift();
}
let items = [];
try {
items = JSON.parse(result[0]);
} catch (e) {
/* eslint no-empty:0 */
}
// console.log(items);
// 演示
const item = items[0];
const uptimeTmp = numeral((new Date() - item.pm2_env.pm_uptime) / 1000)
.format('00:00:00')
.split(':')
.map(Number);
const uptime = `${parseInt(uptimeTmp[0] / 24, 10)}天${uptimeTmp[0] % 24}时${uptimeTmp[1]}分${uptimeTmp[2]}秒`
.replace('0天', '')
.replace('0时', '')
.replace('0分', '')
.replace('0秒', '');
console.log(item.pid);
// 41965
console.log(item.name);
// app-name
console.log(item.pm_id);
// 0
console.log(`${item.monit.cpu}%`);
// 91%
console.log(numeral(item.monit.memory).format('0.0b'));
// 126.8MB
console.log(uptime);
// 6秒
console.log(item.pm2_env.restart_time);
// 0
if (item.monit.cpu > 90) {
exec(`pm2 restart ${item.pm_id}`, (err2, stdout2, stderr2) => {
console.log(stdout2);
console.log(stderr2);
});
}
});