原文地址: http://www.moye.me/?p=496

引子

众所周知,虽然Node的底层有一个IO线程池,但其应用层默认是单线程运行的,对于多核CPU环境来说,是一种资源的浪费。

所幸Node提供了child_process 模块,让开发者得以开多个进程,实现每个进程各自利用一个CPU,以实现多核的利用。

child_process 模块给予Node 可以随意创建子进程的能力。因为 child_process 类本身是一个 EventEmitter,所以进程间通信很容易;且父子进程间通信并不通过网络层,而是在内核中完成,高效。

但 child_process 对于开发者来说,编程模型还是过于复杂,需要操心的细节过多,比如:父进程崩溃了,子进程回收是需要开发者提供代码来处理的——如果开发者只是想单纯利用多核模型,对具体工作进程的控制粒度并没有太多设想,那这种开发模型无疑是令人头疼的。

针对这个问题,Node 提供了 Cluster 模块。Cluster 简化了父子模型编程模型,只区分:当前进程是不是 Master,是 Master 就可以fork子进程,不是那就请行使Worker 职责。至于什么资源的回收,负载的调配,uncaughtException的处理,它自有安排。

本质上, Cluster 是 child_process 和 net 模块的组合应用。它不仅简化了编程模型,还使得共享监听同一端口成为可能。

更多关于Cluster的原理这里不表,感兴趣可以移步 → 解读Nodejs多核处理模块cluster

场景

用Node快速搭站呢,当然就用 express 咯  所以,需求就是用 Cluster 做个单机集群,多进程跑 express,提升站点的吞吐量。

实验

先用 express-generator 搭个框子,模板引擎还是使 ejs 吧:

express -e myapp2

express-generator 默认会把 app.js 生成好,一行代码不写,一个完备的 http server 是已经实现的了。So,我们可以实现一个 Cluster 单机集群,clusterMaster.js:

//CPU几核?
var cpus = require('os').cpus().length; //子进程监听消息处理函数
var workerListener = function (msg) {
if (msg.access)
console.log('user access %s, worker [%d]',
msg.access, msg.workerid);
};
//fork新的子进程函数
var forkWorker = function(listener){
var worker = cluster.fork();
console.log('worker [%d] has been created',
worker.process.pid);
worker.on('message', listener);
return worker;
}; //Cluster处理
var cluster = require('cluster');
if (cluster.isMaster) {
for (var i = 0; i < cpus; i++) {
forkWorker(workerListener);
}
} else {
var app = require('./app');
return app.listen(3000);
} //Cluster收到子进程退出消息
cluster.on('exit', function (worker, code, signal) {
console.log('worker [%d] died %s, fork a new one.',
worker.process.pid, code || signal);
forkWorker(workerListener);
});
//Cluster收到子进程运行消息
cluster.on('online', function(worker){
console.log('worker [%d] is running.', worker.process.pid);
});

可以看到:

  • Cluster 是通过 isMaster 来区分父子进程的。父进程中处理创建逻辑:根据 CPU的核数,创建相应数量的子进程;子进程中运行具体的 Server 创建代码。够简单的模型~
  • 在 Cluster 父进程端,是始终能获知 当前worker 的。而当前 worker 的 pid 呢,在有worker 句柄情况下,对应的是 woker.process.pid;在子进程运行的上下文中,就是 process.pid。这不难理解~
  • 我们为新fork出来的子进程添加了消息处理函数,使得任何子进程运行代码,都可以随时利用消息触发它:用途挺广泛的,稍后会演示一个例子
  • 在子进程退出时,Cluster 父进程会收到 exit 消息,这时会重fork一个新子进程来补缺

假设用户访问这个站点: localhost:3000/,我希望告诉他,是哪个子进程在为他渲染页面。那么,在 /routes/ 添加一个express 路由 index.js:

var express = require('express');
var router = express.Router(); /* GET home page. */
router.get('/', function (req, res) {
res.render('index', { title: 'Express',
workerid: process.pid });
process.send({access: '/', workerid: process.pid});
}); module.exports = router;

可以看到,除了路由,还使用 process.send 发送了消息,它实际上会触发之前代码中子进程注册的 workerListener,向它汇报路径和进程号;由于使用了 render,那自然是少不了 ejs 模板, /views/index.js:

<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<p>[<%= workerid %>] worker is serving for you.</p>
</body>
</html>

模板会将 render 携带的子进程 pid 渲染到页面上; 当然少不了在 app.js 中添加路由映射:

var routes = require('./routes/index');

app.use('/', routes);

运行程序,在 shell 下 看看进程生成情况:

一父四子,试着用 kill 64163杀死一个子进程。可以在console看到,主进程收到了 exit消息,并重新fork一个新的进程:

测试一下负载,用 Chrome 重复访问几次站点,似乎 worker 子进程 一直未变:

用 ab 来模拟一下并发,让它一个核忙不过来:


换 Safari 浏览器访问一下站点,这次换了一个 worker 进程来服务,速度还不慢 

更多文章请移步我的blog新地址: http://www.moye.me/

[Node.js] Cluster,把多核用起来的更多相关文章

  1. node.js cluster模式启用方式

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

  2. node.js cluster多进程、负载均衡和平滑重启

    1 cluster多进程 cluster经过好几代的发展,现在已经比较好使了.利用cluster,可以自动完成子进程worker分配request的事情,就不再需要自己写代码在master进程中rob ...

  3. 深入浅出Node.js(一):什么是Node.js

    Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟Joyent获得企业资助,再到 ...

  4. 读书笔记: 深入浅出node.js

    >> 深入浅出node.js node.js是c++编写的js运行环境 浏览器: 渲染引擎 + js引擎 后端的js运行环境 node.js用google v8引擎,同时提供很多系统级的A ...

  5. 深入浅出Node.js(一):什么是Node.js(转贴)

    以下内容转自:http://www.infoq.com/cn/articles/what-is-nodejs/ 作者:崔康 [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的 ...

  6. node.js内存缓存的性能情况

    1. WEB 服务性能测试和优化 1.1   测试环境搭建 网络环境:内网 压力测试服务器: 服务器系统:Linux 2.6.18 服务器配置:Intel® Xeon™ CPU 3.40GHz 4 C ...

  7. 深入浅出Node.js(上)

    (一):什么是Node.js Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟 ...

  8. Node.js:进程、子进程与cluster多核处理模块

    1.process对象 process对象就是处理与进程相关信息的全局对象,不需要require引用,且是EventEmitter的实例. 获取进程信息 process对象提供了很多的API来获取当前 ...

  9. Node.js的cluster模块——Web后端多进程服务

    众所周知,Node.js是单线程的,一个单独的Node.js进程无法充分利用多核.Node.js从v0.6.0开始,新增cluster模块,让Node.js开发Web服务时,很方便的做到充分利用多核机 ...

随机推荐

  1. Android音频介绍

    这个世界音频设备千变万化,Android也不可能为每种设备都提供支持.Android定义了一个框架,这个框架来适配底层的音频设备.该适配层的定义位于: hardware/libhardware_leg ...

  2. 致第一次安装RIME的你

    转载自百度RIME吧,作者:半月湾C 原帖地址:http://tieba.baidu.com/p/3288634121   序言 很喜欢小狼毫输入法,喜欢他的简洁,美观以及超强悍的个人定制功能.关于 ...

  3. [sicp]huffman编码的实现 @ Scheme

    #lang racket (define (length items) (if (null? items) (+ (length (cdr items))))) (define (element-of ...

  4. 一个非常棒的html5框架-ionic

    http://ionicframework.com/ 之前用过app.js,相比ionic,真是弱爆了! http://learn.ionicframework.com/formulas/ 上面的链接 ...

  5. Scala 深入浅出实战经典 第52讲:Scala中路径依赖代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. 将ASP.NET Core应用程序部署至生产环境中(CentOS7)(转)

    阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. 部署ASP.NET Core应用程序 配置Nginx 配置守 ...

  7. CoreImage 处理图片

    1.CoreImage 滤镜的使用(马赛克模糊) CoreImage是苹果公司为了简化图片处理的难度而开发出来的类库. 随着iOS版本号升级以及硬件性能的不断提升,CoreImage将支持越来越多的滤 ...

  8. android Studio NDK

    官方文档地址: https://developer.android.com/studio/projects/add-native-code.html#download-ndk 最近推出CMake方式集 ...

  9. 《objective-c基础教程》学习笔记(十)—— 内存管理

    本篇博文,将给大家介绍下再Objective-C中如何使用内存管理.一个程序运行的时候,如果不及时的释放没有用的空间内存.那么,程序会越来越臃肿,内存占用量会不断升高.我们在使用的时候,就会感觉很卡, ...

  10. Unity5网络模块UNet介绍

    前段时间,研究了一下UNet,经过项目实践,大致整理了下遇到的问题. 源码Bitbucket:需要说明的是,这个项目只包含上层的包装,一些低层的网络实现在Unity内部,如NetworkTranspo ...