14-04-15
banq
伸缩扩展Node.js应用是一个具有挑战性的任务,Javascript的单线程特性会阻止你的Node使用现代多核应用,比如下面一个基本Http服务器,这个代码无论是在单核还是多核上都是运行在一个线程中。
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); <p class="indent"> |
跨多核扩展
只要稍微做些修改,这段代码就能充分利用多核特点,下面是使用cluster模块进行优化,Cluster允许你方便地创建一个分享端口的进程网络,在这个例子中,每个核对应单独进程,是由numCPU定义,每个子进程然后实现Http服务器,通过监听分享的端口。
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); } <p class="indent"> |
跨多台机器扩展
上面实现了一个机器内跨多核的扩展,下面看看如何跨服务器横向扩展。
扩展多个服务器是通过使用一个反向代理服务器,对进来的请求实现负载平衡。
Nodejitsu 已经开发了node-http-proxy,这是一个NodeJS的开源代理服务器,这个模块通过如下命令安装:
npm install http-proxy <p class="indent"> |
下面是使用案例代码,在这个例子中哦哦那个,负载是在本地服务器两个端口之间进行平衡,在测试反向代理之前,确保原来的Http服务器运行在端口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); <p class="indent"> |
当然,这个案例只是使用了一台服务器,如果你有多台服务器,让你的反向代理服务器运行在一台服务器上,而使用另外一台或几台运行Http服务器。
使用Nginx扩展
使用反向代理当然好,因为它让你的整个软件堆栈都是相同的技术。然而,在生产系统中,更普遍的是使用nginx作为处理负载平衡。 nginx的是一个开放源码的HTTP和反向代理服务器是,它服务于静态文件如CSS和HTML都非常好。因此,nginx可以用来缓存和服务于您的网站的静态内容,同时转发动态内容到Node服务器的请求。
下面是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; } } } <p class="indent"> |
其中配置了upstream 服务器名称为node_app,在两个IP之间平衡:
upstream node_app { server 127.0.0.1:8080; server 127.0.0.1:8081; } <p class="indent"> |
然后定义一下路由,上面配置中/foo就是一个将请求分发到 node_app。具体配置可见有关Nginx反向代理配置。