原文:https://strongloop.com/strongblog/whats-new-in-node-js-v0-12-cluster-round-robin-load-balancing

本文地址:http://www.cnblogs.com/jasonxuli/p/4522134.html

Node.js v0.12的新特性 -- Cluster采用轮询调度算法来进行负载均衡

November 19, 2013 by Ben Noordhuis

欢迎来到由Node的核心提交者 Ben Noordhuis 和 Bert Belder撰写的系列博文的第一篇。本系列可能由7-8篇构成,主要涵盖了Node.js v0.12的新特性。本文主要是关于新的轮询调度集群算法。

回顾Node内置的cluster模式

忆往昔,Node令人扼腕之限制即其内在之单线程模式。不管你的机器有多少核心,Node只会利用一个(同时警告用户,某些操作会利用一个线程池。对于大多数程序来说,相对于总的CPU时间,这只是九牛一毛,因此这样做并不会对利用处理器资源起到真正的帮助)。

这也是Node.js v0.8引入内置的cluster模块的原因。cluster模块让你可以启动一个作为监管者的主进程,以及一个或多个做实际工作的工作进程。

其中的一个目的是使得你更容易创建“甩手掌柜”式的多进程服务器。完美情况下,你应该可以用一个现有的单进程程序制造出足够多的工作进程而不需要修改任何代码。

当然,事情没那么容易。但是cluster模块使得程序有很少甚至没有共享状态,或者可以将共享状态保存在外部资源中,比如数据库或者web service。将程序转换成集群模式基本上只需要几行代码:

var cluster = require('cluster');
var os = require('os'); if (cluster.isMaster)
// Spawn as many workers as there are CPUs in the system.
for (var i = 0, n = os.cpus().length; i < n; i += 1)
cluster.fork();
else
// Start the application.
app();

程序也不需要知道它是在集群模式下运行。
假如你的app()是下面这样:

var http = require('http');

function app() {
var server = http.createServer(function(req, res) {
res.end('OK');
});
server.listen(8080, 'www.example.com');
}

cluster模块的魔力保证了工作进程可以绑定被请求的地址和端口,即使其他工作进程已经监听了。另外,它保证了外部连接被平均分配到监听的工作进程 -- 至少是理论上。

在Node.js v0.8 和 v0.10中,分配外部连接的算法是很直接的。当工作进程调用http.Server#listen()或者net.Server#listen()时,Node.js 发送消息告诉主进程去创建并绑定一个服务端socket并共享给该工作进程。如果已经有了一个被绑定的socket,主进程就跳过创建并绑定的阶段,直接共享已存在的socket给该工作进程。

这意味着所有的工作进程都监听同一个socket。当新的连接进入时,操作系统唤醒某个工作进程。该进程于是接受该连接然后开始工作。

目前一切都好。操作系统收集运行进程的无数指标,应该因此处于决定进程调度的最好位置。

实际情况

现在到了理论遭遇复杂现实的部分。我们逐渐搞清楚了这一点,操作系统认为的“最优”并不总是等于程序猿认为的“最优”。我们已经观察到,特殊情况下,多数连接由两三个进程承接 -- 特别是Linux和Solaris系统。

从操作系统的视角看,这是有道理的:上下文切换(挂起一个进程然后重新激活另一个进程)是一个相当耗资源的操作。如果有多个进程监听同一个socket,那么唤醒最近被阻塞的进程是最聪明的做法,因为执行上下文切换的几率最小。(当然,调度程序是复杂易变的讨厌鬼;上述解释必然只是实际情况的粗略概括,然而某些进程获得偏向对待的基本前提仍然有效)

不是所有的程序都有这个怪异的情况 -- 实际上多数并不会 -- 但是在有问题的那些例子中可以看到负载不均衡的现象。

确认了问题的根源后,我们有一些对应的疗法,但无一令人满意。暂时不监听这socket以便使其他工作进程有机会接受新的连接,这个办法有点儿用,但是不够。获得“特殊照顾”的工作进程接受连接的比例从90%掉到了60-70%,好了点儿,但是还不够。也不用在意这种办法对于程序处理很多短时连接的能力的显著影响。

事情越来越清晰了,就像产生随机数一样,分配连接处理工作太重要了,我们不能靠几率。经过多次讨论后我们达成了一致 -- 这根救命稻草就是直接抛弃目前的方案,整体切换到另外的方案。Node.js v0.11.2版本切换到轮询调度方案的原因就在于此:新的请求连接由主进程接受并选择一个工作进程来处理。

目前选择工作进程的算法并不深奥。就像它的名字那样,是轮询 -- 只是选中下一个可用的工作进程 -- 但是经过核心开发者和用户的测试表明,它工作的很好: 请求连接现在被分配的很平均。后面还有计划把选择算法变成可配置或者基于插件的方式。

如果你想回退到之前的任务分配方式,你可以设置cluster.schedulingPolicy:

var cluster = require('cluster');
// Set this before calling other cluster functions.
cluster.schedulingPolicy = cluster.SCHED_NONE;
cluster.fork();

或者用NODE_CLUSTER_SCHED_POLICY这个环境变量来配置:

$ export NODE_CLUSTER_SCHED_POLICY="none" # "rr" is round-robin
$ node app.js

一次性的方法是:

$ env NODE_CLUSTER_SCHED_POLICY="none" node app.js    

关于Windows

MS Windows是仅有的将旧方法作为默认的平台。Node.js在Windows平台采用的IOCP来最大化性能。虽然多数情况下都不错,但是它使得传递连接的句柄到其他进程的成本很高。也许在libuv中可以绕过这一点,但是还不清楚这样做是否有必要:Windows的端口并没有太受到类似Linux和Solaris那样的影响。

【译】 Node.js v0.12的新特性 -- Cluster模式采用Round-Robin负载均衡的更多相关文章

  1. 【译】 Node.js v0.12的新特性 -- 性能优化

    原文: https://strongloop.com/strongblog/performance-node-js-v-0-12-whats-new/ January 21, 2014/in Comm ...

  2. Node.js V0.12 新特性之性能优化

    v0.12悠长的开发周期(已经过去九个月了,并且还在继续,是有史以来最长的一次)让核心团队和贡献者们有充分的机会对性能做一些优化. 本文会介绍其中最值得注意的几个. http://www.infoq. ...

  3. Node.js V0.12新特性之性能优化

    v0.12悠长的开发周期(已经过去九个月了,并且还在继续,是有史以来最长的一次)让核心团队和贡献者们有充分的机会对性能做一些优化.本文会介绍其中最值得注意的几个. 支持塞住模式的可写流 现在可写流可以 ...

  4. Atitit js版本es5 es6新特性

    Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...

  5. Node.js v0.10.31API手冊-控制台

    Node.js v0.10.31API手冊-文件夹 控制台 Object 用于向 stdout 和 stderr 打印字符.类似于大部分 Web 浏览器提供的 console 对象函数,在这里则是输出 ...

  6. Node.js v0.10.31API手冊-事件

    Node.js v0.10.31API手冊-文件夹 Events(事件) Node里面的很多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStrea ...

  7. 介绍Ext JS 4.2的新特性的《深入浅出Ext JS》上市

    以用户为中心的时代,应用的界面外观变得越来越重要.然而,很多程序员都缺乏美术功底,要开发出界面美观的应用实属不易.Ext JS的出现,为广大程序员解决了这一难题.它有丰富多彩的界面和强大的功能,是开发 ...

  8. atitit.js 各版本 and 新特性跟浏览器支持报告

    atitit.js 各版本 and 新特性跟浏览器支持报告 一个完整的JavaScript实现是由以下3个不同部分组成的 •核心(ECMAScript)--JavaScript的核心ECMAScrip ...

  9. Node.js v0.10.31API手工-DNS

    原版的API品种,这是从以前的翻译和翻译风格不同 Node.js v0.10.31API手冊-文件夹 DNS 使用 require('dns') 引入此模块. dns 模块中的全部方法都使用了 C-A ...

随机推荐

  1. Wps的ppt里 让图片按顺序出现 就是点击一下 出现一张照片

    基本操作能够用两种方法来实现: 方法一.每页幻灯片插入一张图片,幻灯片默认就是单击鼠标切换幻灯片的,所以不用再做其它设置. 方法二.在一页幻灯片中插入多张图片,全选图片(插入图片后,点击图片,Ctrl ...

  2. HttpRequest

    #ifndef __HTTP_REQUEST_H__ #define __HTTP_REQUEST_H__ #include "cocos2d.h" #include " ...

  3. BZOJ 3555: [Ctsc2014]企鹅QQ hash

    3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

  4. Android - 软件自动更新的实现

    转自:http://blog.csdn.net/wwj_748/article/details/8195565 接触到一个很实用的技术,那就是软件自动更新.一般开发者是通过自行在应用平台添加更新版本的 ...

  5. linux下tomcat开机自启动

    tomcat自启动配置: 方法一: vi /etc/rc.local 添加如下一行 /opt/apache-tomcat-7.0.29/bin/startup.sh (脚本绝对路径) 注意:要添加在e ...

  6. Xcode8中Swift3.0适配问题

    写在前面 收到一些小伙伴的来信,觉得可能下边没有表达清楚,先把大家关心的要点在此进行总结,有兴趣的可以看看下边的研究过程,没兴趣的直接看这段即可. Xcode8支持Swift2.3和Swift3.0两 ...

  7. 开发者必备,超实用的PHP代码片段(转)

    此前,研发频道曾发布<直接拿来用,10个PHP代码片段>,得到了网友们的一致好评.本文,笔者将继续分享九个超级有用的PHP代码片段.当你在开发网站.应用或者博客时,利用这些代码能为你节省大 ...

  8. Python学习 之 异常

    1.python中处理异常的方式 #coding:utf8 filename=raw_input("请输入你要操作的文件") try: f=open(filename) print ...

  9. K.Bro Sorting

    Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)Total Submissio ...

  10. 未能加载文件或程序集“Oracle.DataAccess”或它的某一个依赖项.试图加载格式不正确的程序

    .NET:Microsoft Visual Studio 2010 + .NET Framework 3.5 操作系统:windows2008 R2 64 位操作系统 oracle数据库:32位的OD ...