PM2 守护进程

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);
    });
  }
});