玩轉Nodejs的集群


在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進程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM