Pm2

next.js项目使用pm2 reload出现502

月盾

为了使next.js项目能够不宕机,使用了pm2守护进程,既能保证node出现异常情况能够自动重启,也能保证服务器整机重启时自动恢复服务。多年使用下来的确能够良好运行,不过最近却出现了与原本期望不符的情况。

在已经启动next.js项目的情况下,如果需要重启,我使用了pm2 reload appname,实际上没有完美的零停机重启,反而是直接出现服务不可用,访问网站就502,并且一直无法恢复。在查阅pm2 issue后发现确实有这样的bug。

无奈,只能使用pm2 restart来重启应用。

使用pm2一键部署多个服务

月盾
  1. pm2支持远程部署服务,创建文件ecosystem.json,内容形式如:
{
  // Applications part
  "apps" : [{
    "name"      : "API",
    "script"    : "app.js",
    "env": {
      "COMMON_VARIABLE": "true"
    },
    // Environment variables injected when starting with --env production
    // http://pm2.keymetrics.io/docs/usage/application-declaration/#switching-to-different-environments
    "env_production" : {
      "NODE_ENV": "production"
    }
  },{
    "name"      : "WEB",
    "script"    : "web.js"
  }],
  // 部署部分
  // Here you describe each environment
  "deploy" : {
    "production" : {
      "user" : "node",
      // 多主机配置
      "host" : ["212.83.163.1", "212.83.163.2", "212.83.163.3"],
      // 服务使用的分支
      "ref"  : "origin/master",
      // Git 仓库地址
      "repo" : "git@github.com:repo.git",
      // 项目目录
      "path" : "/var/www/production",
      // Can be used to give options in the format used in the configura-
      // tion file.  This is useful for specifying options for which there
      // is no separate command-line flag, see 'man ssh'
      // can be either a single string or an array of strings
      "ssh_options": "StrictHostKeyChecking=no",
      // To prepare the host by installing required software (eg: git)
      // even before the setup process starts
      // 可以使用";"分割多个命令
      // or path to a script on your local machine
      "pre-setup" : "npm install",
      // Commands / path to a script on the host machine
      // This will be executed on the host after cloning the repository
      // eg: placing configurations in the shared dir etc
      "post-setup": "ls -la",
      // Commands to execute locally (on the same machine you deploy things)
      // Can be multiple commands separated by the character ";"
      "pre-deploy-local" : "echo 'This is a local executed command'"
      // Commands to be executed on the server after the repo has been cloned
      "post-deploy" : "npm install && pm2 startOrRestart ecosystem.json --env production"
      // Environment variables that must be injected in all applications on this env
      "env"  : {
        "NODE_ENV": "production"
      }
    },
    "staging" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/development",
      "ssh_options": ["StrictHostKeyChecking=no", "PasswordAuthentication=no"],
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env dev",
      "env"  : {
        "NODE_ENV": "staging"
      }
    }
  }
}

Edit the file according to your needs.

pm2设置NODE_ENV环境变量

月盾

nodejs中经常使用到环境变量,最常见的如:process.env.NODE_ENV。那么在生产环境中使用pm2如何设置环境变量?

设置方式一:shell命令设置

linuxexport NODE_ENV=development&& node app.js

winset NODE_ENV=development&& node app.js

一般是作临时变量在系统启动时设置,不影响其他系统,也可同时运行开发环境和生产环境,只需要根据process.env.NODE_ENV来运行不同逻辑即可。

设置方式二:配置文件设置

要在pm2设置环境变量也很简单。

pm2 start pm2.json –env production

--env production参数是为了设置环境变量,由pm2.json中的配置决定设置什么样的环境变量。

pm2.json

{
  "apps" : [{
    "name": "issue",
    "cwd": "dest",
    "script"    : "bin/www.js",
    "instances" : "2",
    "exec_mode" : "cluster",
    "env": {
      "NODE_ENV": "development",
      "PORT": 3002
    },
    "env_production" : {
       "NODE_ENV": "production",
       "PORT": 3003
    },
    "log_date_format": "YYYY-MM-DD_HH:mm Z",
    "merge_logs": true
  }]
}

如果不加参数则默认使用

"env": {
    "NODE_ENV": "development",
    "PORT": 3002
}

结果:NODE_ENV=development,PORT=3002

--env production则使用的是

"env_production" : {
    "NODE_ENV": "production",
    "PORT": 3003
}

结果:NODE_ENV=production,PORT=3003

再聊docker和nodejs

月盾

上一篇写到了如何在docker中运行nodejs,运行方式是在docker中安装了pm2来保证node服务宕机重启,这种方式更像是把docker当做虚拟机来使用。其实,既然使用了docker的话就可以不使用pm2来管理进程,因为docker自身可以充当守护进程,在node进程退出时进行重启。只要在启动docker容器时加上–restart=always参数即可。例如:docker run -d --restart=always -p 3000:3000 mynode:1

没有pm2如何开启多进程

使用pm2可以开启多node进程,并且自带负载均衡,但是有个限制,pm2可以开启的进程数是CPU最大核心数。而使用docker的话就不会受限于此了,开启几十个上百个node服务都可以,然后通过nginx实现负载均衡。不过要手动开启几十上百个docker容器那怎么行?让我手动开启3个都很烦了,这时候就需要用到docker编排工具了,比如:Docker Swarm、Kubernetes、docker compose等,可以一键开启多个容器。但是使用编排工具启动docker端口就不确定了,是由编排工具随机开启服务端口的,这又要做到服务注册发现,所以这些工具结合起来使用。

哪一种部署方式支持并发高?

使用jmeter在本机上进行了简单的并发测试,服务端进行简单的10万次hash计算,使用pm2开启4个实例,docker开启5个实例。docker使用Nginx做负载均衡,单次访问响应时间在1.2s~1.4s之间不等,在200个并发的情况下,两种模式响应时间相差不大,docker模式响应时间略占优势,大概快了0.1s。当并发数在300以上时两者的响应时间都有增加,此时docker部署方式出现了响应失败的情况,pm2就比较稳定了,虽然响应时间增加,但是并未出现过响应失败。 所以在单机上低并发docker还是有点优势,如果在高并发情况下还是pm2更稳定一些。(以上测试是单机上进行,准确性并不高)

pm2日志记录和日志分割

月盾

pm2介绍

pm2是nodejs进程管理工具,现在基本是node生产服务器的标准选择,可以帮助我们实现node多进程服务,开启的多个实例自动实现负载均衡。 最重要的是保证node单进程不会因为错误退出,作为守护进程保证nodejs服务不宕机。 总体来说就是有性能监控、自动重启、负载均衡的作用。

pm2-logrotate介绍

pm2本身是可以输出日志文件的,默认的文件路径:

error log path    │ /home/username/.pm2/logs/app-error-0.log
out log path      │ /home/username/.pm2/logs/app-out-0.log 

但是pm2的日志文件不能自动分割,这会导致一个文件不断变大,不但影响性能,查看这些日志也会带来麻烦。所以需要pm2-logrotate来实现自动分割日志。

安装pm2-logrotate

pm2 install pm2-logrotate,是用pm2命令,不是npm命令

pm2-logrotate配置

  • max_size (默认 10M): 最大为多少时进行分割,例如: 10G, 10M, 10K
  • retain (Defaults to all): This number is the number of rotated logs that are keep at any one time, it means that if you have retain = 7 you will have at most 7 rotated logs and your current one.
  • compress (默认 false): 是否压缩日志
  • dateFormat (默认 YYYY-MM-DD_HH-mm-ss) : 日志格式
  • rotateModule (Defaults to true) : Rotate the log of pm2’s module like other apps
  • workerInterval (Defaults to 30 in secs) : You can control at which interval the worker is checking the log’s size (minimum is 1)
  • rotateInterval (Defaults to 0 0 * * * everyday at midnight): This cron is used to a force rotate when executed. We are using node-schedule to schedule cron, so all valid cron for node-schedule is valid cron for this option. Cron style :
  • TZ (Defaults to system time): This is the standard tz database timezone used to offset the log file saved. For instance, a value of Etc/GMT-1, with an hourly log, will save a file at hour 14 GMT with hour 13 GMT-1 in the log name.
*    *    *    *    *    *
┬    ┬    ┬    ┬    ┬    ┬
│    │    │    │    │    |
│    │    │    │    │    └ day of week (0 - 7) (0 or 7 is Sun)
│    │    │    │    └───── month (1 - 12)
│    │    │    └────────── day of month (1 - 31)
│    │    └─────────────── hour (0 - 23)
│    └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)

可以尝试使用pm2 set pm2-logrotate:max_size 1K (1KB)设置日志文件最大为1KB 代码中console.log的内容会输出到 /home/username/.pm2/logs/app-out-0.log, 大小达到1KB就会自动生成 app-out-0__2018-01-25_16-58-16.log这种格式的日志文件。 在/home/username/.pm2/logs/(默认路径,可以配置)路径下还有

在docker中运行nodejs

月盾

首先看项目目录:

项目目录

再看Dockerfile文件内容:

# 以最新的node为基础镜像
FROM hub.c.163.com/library/node:latest
# 工作目录为app
WORKDIR /app
# 拷贝当前所在项目根目录到app目录
COPY . /app
# 全局安装pm2
RUN npm install pm2 -g

EXPOSE 8081
#使用pm2启动nodejs,如果没有--no-daemon参数docker启动后就退出
CMD ["pm2-runtime", "dest/server.js", "--no-daemon"]
# ENTRYPOINT ["node", "server.js"]

或者在Dockerfile中不添加CMD命令,可以在启动docker时执行命令:

docker run --name ks -ti -p 8081:8081 kser:pm2 pm2-runtime dest/server.js

如果是后台运行的docker:

docker run --name ks -d -p 8081:8081 kser:pm2 pm2-runtime dest/server.js

-d选项是后台运行

需要进入到docker查看pm2运行情况 ,可以通过docker exec -ti ks /bin/sh查看运行的容器内部情况 pm2运行情况

要不要在docker中使用pm2运行nodejs

  • pm2可以监控nodejs进程,如果进程挂了,可以自动重启
  • pm2可以设置启动的nodejs进程个数,提高服务性能
  • pm2可以设置日志记录
  • pm2可以设置端口,避免端口冲突

docker已经提供了自动重启的功能,可以这样启动nodejs服务:

docker run --name ks -d --restart=always -p 8081:8081 kser:pm2 pm2-runtime dest/server.js

pm2的fork模式和cluster模式的区别

月盾

pm2的fork模式和cluster模式的区别

fork模式

pm2默认启动的是fork模式,是以单核单进程运行的,在fork模式下可以直接运行coffee-script,PHP,python。 参考:http://pm2.keymetrics.io/docs/tutorials/using-transpilers-with-pm2 运行非js语言必须设置运行模式为fork_mode

cluster模式

cluster模式可以根据CPU数量进行实例扩展,可以开启多进程而不需要修改代码。可提高程序性能和可靠性。类似于分布式系统,只不过是在单台机器上开启多实例,而pm2自带负载均衡。

** 使用方法 ** pm2 start app.js -i max 使用-i参数,max代表最大CPU进程数

也可以使用文件方式: processes.json文件:

{
  "apps" : [{
    "script"    : "api.js",
    "instances" : "max",
    "exec_mode" : "cluster" 
  }]
}

pm2 start processes.json

pm2在线监控

月盾

先来一张效果图:

](https://hopefully-img.yuedun.wang/172722906.png)

由图可以看出,监控内容有CPU,内存使用,系统bug,以及代码更新和重启服务,还有更多功能,比如bug邮件提醒功能。

使用方法很简单,几乎是一条命令搞定,首先打开https://app.keymetrics.io/#/

注册登录以后应该可以看到下图命令提示,在服务器中执行第一条命令,需要带后面的machine name

可能会失败,多试几次就可以了。然后再web页面会自动出现服务器状况。