在Nodejs中使用集群还是不容易的。Javascript的单线程属性让nodejs下的应用很难使用现代机器的多核特性。比如下面的代码实现了一个http服务器的主干部分。这部分代码只会执行在一个线程上,不管这段代码运行的机器是单核的cpu还是1000个内核的cpu。

var http = require("http");
var port = parseInt(process.argv[2]); http.createServer(function(request, response) {
console.log("Request for: " + request.url);
response.writeHead(200);
response.end("hello world\n");
}).listen(port);

使用多核特性

只需要一点修改,上面的代码就可以把cpu的所有核心都用起来。上面的示例代码将使用cluster模块重构。cluster模块可以让你很容易的创建多个分享端口的进程。每一个进程使用一个系统核心,也就是代码中的numCPUs变量中cpu核心的一个。每一个子进程都实现了HTTP server,并监听指定的端口。

var cluster = require("cluster");
var http = require("http");
var numCPUs = require("os").cpus().length;
var port = parseInt(process.argv[2]); if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
} cluster.on("exit", function(worker, code, signal) {
cluster.fork();
});
} else {
http.createServer(function(request, response) {
console.log("Request for: " + request.url);
response.writeHead(200);
response.end("hello world\n");
}).listen(port);
}

多机器的均衡

使用cluster模块,你就可以更高效的使用硬件。然而,你还是被限制在单一的机器上。如果你的应用有客观的访问量,你最终还是把负载分部在不同的机器上。使用reverse proxy server可以把并发的访问负载到不同的服务器上。

Nodejitsu开发了node-http-proxy模块,一个开源的nodejs应用代理服务。使用以下命令可以安装这个模块:

npm install http-proxy

实际的使用可以参考以下代码。在这里例子中负载被分发到两台服务器上。首先测试反转代理,确保HTTP server运行在8080和8081两个端口上。接下来,运行反转代理,然后用浏览器访问这个代理。如果一切正常的话,你会发现请求被两个服务器交替处理。

var proxyServer = require('http-proxy');
var port = parseInt(process.argv[2]);
var servers = [
{
host: "localhost",
port: 8081
},
{
host: "localhost",
port: 8080
}
]; proxyServer.createServer(function (req, res, proxy) {
var target = servers.shift(); proxy.proxyRequest(req, res, target);
servers.push(target);
}).listen(port);

当然,这个例子只使用了一台机器。然而,如果你有多台机器的话,你可以在一台机器上运行反向代理服务器,其他的机器上运行HTTP server。

使用nginx负载均衡

使用nodejs写的反向代理有一个好处是你使用的技术都是一样的。但是,在生产环境下,更多使用的是nginx来处理负载均衡。nginx是一个开源的HTTP server和反向代理工具,尤其擅长处理静态文件,比如:CSS和HTML。因此,nginx常被用于处理站点的静态文件,和分发动态请求到nodejs的服务器上。

要实现nginx的负载均衡,只需要安装nginx,之后把nodejs服务器作为upstream resource添加在配置文件中。配置文件的路劲一般是{nginx-root}/conf/nginx.conf,{nginx-root}是nginx安装的根目录。整个的配置文件请参考下面的示例。当然,我们只需要用到其中的一小部分。

#user  nobody;
worker_processes 1; #error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info; #pid logs/nginx.pid; events {
worker_connections 1024;
} http {
include mime.types;
default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on;
#tcp_nopush on; #keepalive_timeout 0;
keepalive_timeout 65; #gzip on; upstream node_app {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
} server {
listen 80;
server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / {
root html;
index index.html index.htm;
} location /foo {
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://node_app;
} #error_page 404 /404.html; # redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
} # proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#} # deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
} # another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias; # location / {
# root html;
# index index.html index.htm;
# }
#} # HTTPS server
#
#server {
# listen 443;
# server_name localhost; # ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key; # ssl_session_timeout 5m; # ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on; # location / {
# root html;
# index index.html index.htm;
# }
#} }

如前文所述,本教程只会涉及到整个配置文件的一部分。第一个需要关注的部分如下所示。

upstream node_app {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}

这部分的配置定义了一个upstream服务器,名称为node_app。对这个服务器的请求会分配到就两个ip地址上(这里只用端口区分了一下)。

只是定义了一个upstream服务器还没有告诉nginx如何使用它。因此,我们必须使用如下的指令顶一个路由的规则。使用这个路由,任何的到/foo的请求都会被代理到之前配置的nodejs服务器上。

location /foo {
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://node_app;
}

最后

本教程旨在介绍如何把单线程的Nodejs应用运行在多台机器的多个核心上。你也可以学到如何使用nodejs或者nginx建立一个负载均衡。当然本文不是深入的介绍如何在产品环境下运行的。因此,如果你使用的是nginx,还有很多其他的可以做的,比如缓存,来提高系统性能。你也会需要使用forever,如果崩溃的话这个工具可以重启你的nodejs进程。

玩转Nodejs的集群的更多相关文章

  1. 玩转nodeJS系列:使用原生API实现简单灵活高效的路由功能(支持nodeJs单机集群),nodeJS本就应该这样轻快

    前言: 使用nodeJS原生API实现快速灵活路由,方便与其他库/框架进行整合: 1.原生API,简洁高效的轻度封装,加速路由解析,nodeJS本就应该这样轻快 2.不包含任何第三方库/框架,可以灵活 ...

  2. 玩转 Redis缓存 集群高可用

    转自:https://segmentfault.com/a/1190000008432854 Redis作为主流nosql,在高并发使用场景中都会涉及到集群和高可用的问题,有几种持久化?场景下的缓存策 ...

  3. Apache+Tomcat +mod_proxy集群负载均衡及session

      序言: 在玩Apache+Tomcat +mod_jk集群负载均衡及session的时候发现,还有一种方式可以实现,就是网上各位大牛们说的mod_proxy反向代理. 实在弄的我的知识细胞洋洋.实 ...

  4. 玩转nodeJS系列:使用cluster创建nodejs单机多核集群(多进程)

    前言: nodejs提供了cluster集群(支持端口共享的多进程),cluster基于child_process,process二次封装,方便我们使用该功能实现单机nodejs的web集群. 1.c ...

  5. 如何创建 Swarm 集群?- 每天5分钟玩转 Docker 容器技术(95)

    本节我们将创建三节点的 swarm 集群. swarm-manager 是 manager node,swarm-worker1 和 swarm-worker2 是 worker node. 所有节点 ...

  6. 5 秒创建 k8s 集群 - 每天5分钟玩转 Docker 容器技术(115)

    据说 Google 的数据中心里运行着超过 20 亿个容器,而且 Google 十年前就开始使用容器技术. 最初,Google 开发了一个叫 Borg 的系统(现在命令为 Omega)来调度如此庞大数 ...

  7. 菜鸟玩云计算之十九:Hadoop 2.5.0 HA 集群安装第2章

    菜鸟玩云计算之十九:Hadoop 2.5.0 HA 集群安装第2章 cheungmine, 2014-10-26 在上一章中,我们准备好了计算机和软件.本章开始部署hadoop 高可用集群. 2 部署 ...

  8. 菜鸟玩云计算之十八:Hadoop 2.5.0 HA 集群安装第1章

    菜鸟玩云计算之十八:Hadoop 2.5.0 HA 集群安装第1章 cheungmine, 2014-10-25 0 引言 在生产环境上安装Hadoop高可用集群一直是一个需要极度耐心和体力的细致工作 ...

  9. Kubernetes 集群日志管理 - 每天5分钟玩转 Docker 容器技术(180)

    Kubernetes 开发了一个 Elasticsearch 附加组件来实现集群的日志管理.这是一个 Elasticsearch.Fluentd 和 Kibana 的组合.Elasticsearch ...

随机推荐

  1. Technology, globalisation and the squeeze on good jobs

    Technology, globalisation and the squeeze on good jobs技术与全球化冲击好工作“Highest stock market EVER! Jobs ar ...

  2. Docker之My sql 之旅

    要用到mysql 数据库,本来想在本机装,后来想想还是有点污染环境,既然有docker为什么不用呢? 于是开启了采坑之旅,与其说采坑,倒不如说看文档不仔细看. docker pull mysql:5. ...

  3. MongoDB 数据库命令

    数据库命令 连接成功后,默认使用test数据库 查看当前数据库名称 db 查看所有数据库名称,列出所有在物理上存在的数据库 show dbs 切换数据库,如果数据库不存在也并不创建,直到插入数据或创建 ...

  4. 如何使用Python画地图数据

    http://blog.csdn.net/wen_fei/article/details/78355699

  5. tesseract 4.0 编译安装(CentOS)

    1.安装依赖工具 yum install autoconf automake libtool libjpeg-devel libpng-devel libtiff-devel zlib-devel 2 ...

  6. nfs只能挂载为nobody的解决方法

    不得不承认centos6较centos5发生了很大的变化,在新部署的centos 6.4上又遇到nfs挂载的问题.问题现象是,在配置完nfs后,无论配置里指定的是何用户,挂载成功后显示的只能是nobo ...

  7. MySql频繁查询、插入数据

    当我们需要频繁地从数据库查询.插入数据时,可以将这些数据库操作汇集写到同一个类里,作为工具类直接调用. 将数据库的具体信息保存在.properties文件中,用log4j作为日志记录 MySql.ja ...

  8. Python repr() 函数

    Python repr() 函数  Python 内置函数 描述 repr() 函数将对象转化为供解释器读取的形式. 语法 以下是 repr() 方法的语法: repr(object) 参数 obje ...

  9. tf.random_normal()

    tf.random_normal()函数用于从服从指定正太分布的数值中取出指定个数的值. tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf. ...

  10. INI

    .ini 文件是Initialization File的缩写,即初始化文件,是windows的系统配置文件所采用的存储格式,统管windows的各项配置,一般用户就用windows提供的各项图形化管理 ...