[Node.js] Cluster,把多核用起来
原文地址: 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,把多核用起来的更多相关文章
- node.js cluster模式启用方式
众所周知,Node.js运行在Chrome的JavaScript运行时平台上,我们把该平台优雅地称之为V8引擎.不论是V8引擎,还是之后的Node.js,都是以单线程的方式运行的,因此,在多核心处理器 ...
- node.js cluster多进程、负载均衡和平滑重启
1 cluster多进程 cluster经过好几代的发展,现在已经比较好使了.利用cluster,可以自动完成子进程worker分配request的事情,就不再需要自己写代码在master进程中rob ...
- 深入浅出Node.js(一):什么是Node.js
Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟Joyent获得企业资助,再到 ...
- 读书笔记: 深入浅出node.js
>> 深入浅出node.js node.js是c++编写的js运行环境 浏览器: 渲染引擎 + js引擎 后端的js运行环境 node.js用google v8引擎,同时提供很多系统级的A ...
- 深入浅出Node.js(一):什么是Node.js(转贴)
以下内容转自:http://www.infoq.com/cn/articles/what-is-nodejs/ 作者:崔康 [编者按]:Node.js从2009年诞生至今,已经发展了两年有余,其成长的 ...
- node.js内存缓存的性能情况
1. WEB 服务性能测试和优化 1.1 测试环境搭建 网络环境:内网 压力测试服务器: 服务器系统:Linux 2.6.18 服务器配置:Intel® Xeon™ CPU 3.40GHz 4 C ...
- 深入浅出Node.js(上)
(一):什么是Node.js Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟 ...
- Node.js:进程、子进程与cluster多核处理模块
1.process对象 process对象就是处理与进程相关信息的全局对象,不需要require引用,且是EventEmitter的实例. 获取进程信息 process对象提供了很多的API来获取当前 ...
- Node.js的cluster模块——Web后端多进程服务
众所周知,Node.js是单线程的,一个单独的Node.js进程无法充分利用多核.Node.js从v0.6.0开始,新增cluster模块,让Node.js开发Web服务时,很方便的做到充分利用多核机 ...
随机推荐
- 《Windows核心编程》学习笔记(9)– 在win7或者vista系统下提升一个进程的运行权限
win7或者vista默认运行程序是在受限制的环境下运行的,以减轻病毒对于系统的破坏.那么我们怎样才能提升一个进程的权限以至让它在 管理员模式下运行.当然CreateProcess函数没有提供这个功能 ...
- android: 播放音频
在 Android 中播放音频文件一般都是使用 MediaPlayer 类来实现的,它对多种格式的音 频文件提供了非常全面的控制方法,从而使得播放音乐的工作变得十分简单.下表列出了 MediaPlay ...
- Swift入门篇-闭包和函数
今天主要是给大家分享的是 swift中闭包的用法,我个人觉得闭包就是函数的简写方法,如果您函数不是很熟悉请查阅 swift入门篇-函数 1:函数类型 函数类型 var 变量 :(类型)->返回值 ...
- RTP-RTCP-RTSP协议的区别与联系
一.产生的背景 随着互连网的发展,人们已经不满足于传统的HTTP,FTP和电子邮件等文本信息和服务,而对内容丰富多彩的多媒体信息,服务以及多媒体通信方式提出了需求,包括声音,图象,图形,视频信息等等, ...
- Fiddler高级技巧 - 映射路径到本地文件夹
适用场景: 你是前端开发人员,要开发一个小模块,需要用到线上的环境(账号.数据.跨域等),但你又没有权限往线上传文件 你是移动测试人员,需要将一组接口的返回结果替换为另一组,最简单的办法就是使用Fid ...
- 美行Thinkpad八通道快捷入口
美行Thinkpad八通道快捷入口 链接: http://shop.lenovo.com/perksoffer/us/en/laptops/thinkpad/?__followRobots=true打 ...
- 正则指引-字符组demo
class Program { static void Main(string[] args) { string str = "b"; var result1 = Regex.Is ...
- iis7下iis安全狗不能用怎么办(安装iis6兼容性)
is7下iis安全狗不能用怎么办 | 浏览:126 | 更新:2015-05-14 17:11 1 2 3 4 5 6 分步阅读 windows系统iis安全狗是常用的一款软件,针对网站使用很方便.在 ...
- Oracle 数据库表同步方法浅议
总结一下Oracle数据库表级别的复制同步 一.通过触发器进行表的复制 原理,是监听表上都某一字段进行的DML操作,然后得到DML操作的数据,重新在另一个表上执行DML操作. 优点: 简单,编写一个触 ...
- ORA-01654 索引 无法通过 表空间扩展
"ORA-01654: 索引VGSM.AUDIT_DATA_I无法通过8192(在表空间KLDB中)扩展" 1.有可能是索引表空间不够 select sum(bytes/102 ...