在Nodejs中使用集羣仍是不容易的。Javascript的單線程屬性讓nodejs下的應用很難使用現代機器的多核特性。好比下面的代碼實現了一個http服務器的主幹部分。這部分代碼只會執行在一個線程上,無論這段代碼運行的機器是單核的cpu仍是1000個內核的cpu。php
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);
使用多核特性html
只須要一點修改,上面的代碼就能夠把cpu的全部核心都用起來。上面的示例代碼將使用cluster模塊重構。cluster模塊可讓你很容易的建立多個分享端口的進程。每個進程使用一個系統核心,也就是代碼中的numCPUs變量中cpu核心的一個。每個子進程都實現了HTTP server,並監聽指定的端口。node
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); }
多機器的均衡nginx
使用cluster模塊,你就能夠更高效的使用硬件。然而,你仍是被限制在單一的機器上。若是你的應用有客觀的訪問量,你最終仍是把負載分部在不一樣的機器上。使用reverse proxy server能夠把併發的訪問負載到不一樣的服務器上。npm
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負載均衡session
使用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進程。