详解如何使用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 相关文章推荐
Array对象方法参考
Oct 03 Javascript
syntaxhighlighter 使用方法
Jul 02 Javascript
JS左右无缝滚动(一般方法+面向对象方法)
Aug 17 Javascript
Jquery实现仿新浪微博获取文本框能输入的字数代码
Feb 22 Javascript
修改file按钮的默认样式实现代码
Apr 23 Javascript
鼠标移到导航当前位置的LI变色处于选中状态
Aug 23 Javascript
js中数组(Array)的排序(sort)注意事项说明
Jan 24 Javascript
jquery层级选择器(匹配父元素下的子元素实现代码)
Sep 05 Javascript
vue组件 $children,$refs,$parent的使用详解
Jul 31 Javascript
vue-froala-wysiwyg 富文本编辑器功能
Sep 19 Javascript
公众号SVG动画交互实战代码
May 31 Javascript
vue实现简单数据双向绑定
Apr 28 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程序中的常见漏洞进行攻击
2006/10/09 PHP
php使用array_rand()函数从数组中随机选择一个或多个元素
2014/04/28 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
2014/09/02 PHP
深入浅析yii2-gii自定义模板的方法
2016/04/26 PHP
php基于curl实现的股票信息查询类实例
2016/11/11 PHP
PHP封装XML和JSON格式数据接口操作示例
2019/03/06 PHP
Swoole实现异步投递task任务案例详解
2019/04/02 PHP
IE php关于强制下载文件的代码
2008/08/23 Javascript
node.js中的path.isAbsolute方法使用说明
2014/12/08 Javascript
基于jquery实现的树形菜单效果代码
2015/09/06 Javascript
12种JavaScript常用的MVC框架比较分析
2015/11/16 Javascript
详解AngularJS中$http缓存以及处理多个$http请求的方法
2016/02/06 Javascript
jQuery增加与删除table列的方法
2016/03/01 Javascript
JavaScript中闭包的写法和作用详解
2016/06/29 Javascript
Vue应用部署到服务器的正确方式
2017/07/15 Javascript
jQuery+Cookie实现切换皮肤功能【附源码下载】
2018/03/25 jQuery
微信小程序开发之左右分栏效果的实例代码
2019/05/20 Javascript
vue-cli在 history模式下的配置详解
2019/11/26 Javascript
详解vue-router的Import异步加载模块问题的解决方案
2020/05/13 Javascript
[02:41]DOTA2英雄基础教程 谜团
2013/12/10 DOTA
Django添加feeds功能的示例
2018/08/07 Python
利用Pyhton中的requests包进行网页访问测试的方法
2018/12/26 Python
Python自动生成代码 使用tkinter图形化操作并生成代码框架
2019/09/18 Python
Python基于wordcloud及jieba实现中国地图词云图
2020/06/09 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
W Concept美国:精选全球独立设计师
2017/02/22 全球购物
利物浦足球俱乐部官方网上商店:Liverpool FC Official Store
2018/01/13 全球购物
MySQL面试题
2014/01/12 面试题
Hashtable 添加内容的方式有哪几种,有什么区别?
2012/04/08 面试题
公司晚会主持词
2014/03/22 职场文书
《风娃娃》教学反思
2014/04/19 职场文书
中学生操行评语大全
2014/04/24 职场文书
化工工艺设计求职信
2014/06/25 职场文书
高中物理教学反思
2016/02/19 职场文书
2016年学校“3.12”植树节活动总结
2016/03/16 职场文书