详解如何使用PM2将Node.js的集群变得更加容易


Posted in Javascript onNovember 15, 2017

介绍

众所周知,Node.js运行在Chrome的JavaScript运行时平台上,我们把该平台优雅地称之为V8引擎。不论是V8引擎,还是之后的Node.js,都是以单线程的方式运行的,因此,在多核心处理器的系统中并不能发挥其最大的性能。

Node.js的cluster模块

幸运的是,Node.js给我们提供了cluster模块,它可以生成多个工作线程来共享同一个TCP连接。

它是如何运作的呢?

首先,Cluster会创建一个master,然后根据你指定的数量复制出多个server app(也被称之为工作线程)。它通过IPC通道与工作线程之间进行通信,并使用内置的负载均衡来更好地处理线程之间的压力,该负载均衡使用了Round-robin算法(也被称之为循环算法)。

当使用Round-robin调度策略时,master accepts()所有传入的连接请求,然后将相应的TCP请求处理发送给选中的工作线程(该方式仍然通过IPC来进行通信)。

那如何来使用呢?

下面是一个最基本的例子:

var cluster = require('cluster'); 
var http  = require('http'); 
var os   = require('os');

var numCPUs = os.cpus().length;

if (cluster.isMaster) { 
 // Master:
 // Let's fork as many workers as you have CPU cores

 for (var i = 0; i < numCPUs; ++i) {
  cluster.fork();
 }
} else {
 // Worker:
 // Let's spawn a HTTP server
 // (Workers can share any TCP connection.
 // In this case its a HTTP server)

 http.createServer(function(req, res) {
  res.writeHead(200);
  res.end("hello world");
 }).listen(8080);
}

当然,你可以指定任意数量的工作线程,线程的数量不仅限于CPU核心的数量,因为它只是作为一个运行在CPU上的子线程。

正如你所看到的,要使其正常运行,你需要将你的代码封装到cluster的处理逻辑中,并添加一些额外的代码来指定当一个线程挂掉之后如何进行处理。

使用PM2的方式

内置的cluster

PM2内部包含了所有上述的处理逻辑,因此你不必对代码做任何修改。我们将上面的代码还原成最原始的形式:

var http = require('http');

http.createServer(function(req, res) { 
 res.writeHead(200);
 res.end("hello world");
}).listen(8080);

然后在控制台执行:

$ pm2 start app.js -i 4

-i <number of workers>参数用来告诉PM2以cluster_mode的形式运行你的app(对应的叫fork_mode),后面的数字表示要启动的工作线程的数量。如果给定的数字为0,PM2则会根据你CPU核心的数量来生成对应的工作线程。

详解如何使用PM2将Node.js的集群变得更加容易

不论什么情况下,保持你的apps一直运行

如果任意一个工作线程挂掉了,不用担心,PM2会立即将其重启。当然,你也完全可以在任何时候手动重启这些线程:

详解如何使用PM2将Node.js的集群变得更加容易

实时扩展集群

任何时候,如果你需要增加工作线程的数量,可以通过pm2 scale <app name> <n>来对集群进行扩展。参数<n>指定工作线程的数量,被用来增加或减少集群数。你也可以通过pm2 scale app +3的方式来指定要增加多少工作线程。

详解如何使用PM2将Node.js的集群变得更加容易

在产品环境实现零停机更新

PM2的reload <app name>功能将依次重启所有的工作线程。每一个线程会等待在新的线程创建之后才会被终止掉,因此,当你在产品环境部署新的代码时,server会不间断地一直保持运行。

使用gracefulReload功能可以达到相同的目的,不同的是它不会立即终止工作线程,而是通过IPC发送一个shutdown信号来关闭所有当前的连接并处理一些自定义的任务,然后再优雅地退出。如下面的代码:

process.on('message', function(msg) { 
 if (msg === 'shutdown') {
  close_all_connections();
  delete_cache();
  server.close();
  process.exit(0);
 }
});

将PM2配置成自动启动

想要PM2在服务器重启后自动运行之前的应用,可以先通过pm2 start启动你的应用,然后执行下面的命令:

pm2 save

这将在~/.pm2目录下生成一个dump.pm2文件,里面描述了当前PM2上运行着的所有应用。然后执行命令:

pm2 startup [platform]

注意有必要添加可选参数platform以明确告知pm2当前的系统环境。这样,下次当服务器重启时,PM2会自动运行之前保存的应用。

结论

Cluster模块的功能非常强大,使用PM2会使它变得更加容易。在Node 0.10.x时代cluster.js还只是个试验品,但从Node 0.11.x开始已经逐渐成熟并开始准备正式发布,当然也包括Node 0.12.x版本。强烈推荐使用最新版的Node.js和PM2,这些产品的贡献者们一直在努力并使它们变得更好。

尽情享受PM2带给Node.js集群操作的便利吧!

原文地址:https://keymetrics.io/2015/03/26/pm2-clustering-made-easy/

更多有关PM2的安装和使用可以查看这里的文档:http://pm2.keymetrics.io/docs/usage/quick-start/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery 合并内容相同的单元格(示例代码)
Dec 13 Javascript
Javascript加载速度慢的解决方案
Mar 11 Javascript
node+express+jade制作简单网站指南
Nov 26 Javascript
vue组件间通信解析
Mar 01 Javascript
基于JavaScript实现类名的添加与移除
Apr 23 Javascript
WdatePicker.js时间日期插件的使用方法
Jul 26 Javascript
vue教程之toast弹框全局调用示例详解
Aug 24 Javascript
JavaScript基础进阶之数组方法总结(推荐)
Sep 04 Javascript
AngularJS 打开新的标签页实现代码
Sep 07 Javascript
mpvue实现左侧导航与右侧内容的联动
Oct 21 Javascript
微信小程序实现导航栏和内容上下联动功能代码
Jun 29 Javascript
vue 使用 v-model 双向绑定父子组件的值遇见的问题及解决方案
Mar 01 Vue.js
vuejs实现本地数据的筛选分页功能思路详解
Nov 15 #Javascript
Js判断H5上下滑动方向及滑动到顶部和底部判断的示例代码
Nov 15 #Javascript
实现div内部滚动条滚动到底部和顶部的代码
Nov 15 #Javascript
js 原生判断内容区域是否滚动到底部的实例代码
Nov 15 #Javascript
实现div滚动条默认最底部以及默认最右边的示例代码
Nov 15 #Javascript
判断div滑动到底部的scroll实例代码
Nov 15 #Javascript
Vue.js实现列表清单的操作方法
Nov 15 #Javascript
You might like
自动生成文章摘要的代码[PHP 版本]
2007/03/20 PHP
ThinkPHP访问不存在的模块跳转到404页面的方法
2014/06/19 PHP
PHP+redis实现添加处理投票的方法
2015/11/14 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
2016/01/09 PHP
PHP 将数组打乱 shuffle函数的用法及简单实例
2016/06/17 PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
2019/12/12 PHP
Javascript的IE和Firefox兼容性汇编
2006/07/01 Javascript
通过event对象的fromElement属性解决热区设置主实体的一个bug
2008/12/22 Javascript
Javascript 中文字符串处理额外注意事项
2009/11/15 Javascript
Fixie.js 自动填充内容的插件
2012/06/28 Javascript
使用GruntJS链接与压缩多个JavaScript文件过程详解
2013/08/02 Javascript
JS图像无缝滚动脚本非常好用
2014/02/10 Javascript
javaScript知识点总结(必看篇)
2016/06/10 Javascript
第一次接触神奇的Bootstrap
2016/10/14 Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
2016/12/27 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
2018/07/23 jQuery
怎样使你的 JavaScript 代码简单易读(推荐)
2019/04/16 Javascript
解决VUE-Router 同一页面第二次进入不刷新的问题
2020/07/22 Javascript
Python使用urllib2模块实现断点续传下载的方法
2015/06/17 Python
对python生成业务报表的实例详解
2019/02/03 Python
python日志logging模块使用方法分析
2019/05/23 Python
Golang GBK转UTF-8的例子
2019/08/26 Python
python利用JMeter测试Tornado的多线程
2020/01/12 Python
Python爬取YY评级分数并保存数据实现过程解析
2020/06/01 Python
Python爬虫过程解析之多线程获取小米应用商店数据
2020/11/14 Python
Python的Tqdm模块实现进度条配置
2021/02/24 Python
html5触摸事件判断滑动方向的实现
2018/06/05 HTML / CSS
世界上最大的各式箱包网络零售店:eBag
2016/07/21 全球购物
Sahajan美国:阿育吠陀护肤品牌
2021/01/09 全球购物
Sisley法国希思黎美国官方网站:享誉全球的奢华植物美容品牌
2020/06/27 全球购物
使用C#编写创建一个线程的代码
2013/01/22 面试题
单位消防安全制度
2014/01/12 职场文书
高三霸气励志标语
2014/06/24 职场文书
学校群众路线专项整治方案
2014/10/31 职场文书
少年的你:世界上没有如果,要在第一次就勇敢的反抗
2019/11/20 职场文书