伸縮擴充套件Node.JS應用

banq發表於2014-04-15


伸縮擴充套件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反向代理配置。


相關文章