集羣clusterfork運行Node.js

 使用Node.js最大的原因是因為簡化,通過使用單線程範式,從而避免了多線程環境中複雜的線程編程,比如資源競爭和死鎖。當然,以單線程方式運行一個Web伺服器的缺點是隻能利用單核CPU,而現在基本進入了多核時代,這就對資源造成了浪費,而通過Node.js的集羣Cluster方式很容易更好地利用資源。

當你以集羣方式運行Node.js時,將會跨多個處理器,這會更加穩定,因為在單進程情況下,當你的應用遭遇錯誤時,只能重新啟動進程,在這段重啟時間內,你的服務就中斷了,集羣方式可以保持一個主進程時刻了解它的子進程是否失敗,會在其失敗情況下自動將其請求轉發到其他子進程,一直到失敗的子進程重新啟動。

加入集羣非常容易,假設我們下面一段代碼:

var express = require("express"); var app = express(); app.get("/", function(req, res) { res.send("Hello World!"); }); var server = app.listen(3000, function() { console.log("Server started on port 3000"); });

下面命令是是安裝啟動:

npm install express node server

在瀏覽器打開http://localhost:3000會得到hello world。

下面是加入集羣方式的代碼:

var cluster = require("cluster"); if (cluster.isMaster) { var numCPUs = require("os").cpus().length; for (var i = 0; i < numCPUs; i++) { cluster.fork(); } } else { var express = require("express"); var app = express(); app.get("/", function(req, res) { res.send("Hello World!"); }); var server = app.listen(3000, function() { console.log("Server started on port 3000"); }); }

這段代碼主要增加了cluster,當應用啟動後,將自己作為主進程,主進程根據CPU個數創建一個或多個子進程,一般情況下,子進程個數等於CPU的核數,主進程自己不是一個伺服器,它只是負責創建和維護子進程,因為如果主進程也對外服務,一旦其失敗,所有子進程都會失敗。

重啟

 如果一個子進程失敗了,主進程能夠重啟啟動它,代碼如下:

var cluster = require("cluster"); if (cluster.isMaster) { var numCPUs = require("os").cpus().length; for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on("exit", function() { console.log("A worker process died, restarting..."); cluster.fork(); }); } else { var express = require("express"); var app = express(); app.get("/", function(req, res) { res.send("Hello World!"); }); app.get("/explode", function(req, res) { setTimeout(function() { res.send(this.wont.go.over.well); }, 1); }); var server = app.listen(3000, function() { console.log("Server started on port 3000"); }); }

當你訪問http://localhost:3000/explode時,你會引起一個子進程錯誤,會看到控制端的堆棧跟蹤,但是你的應用還是在運行,但是如果你載入explode頁面多次,你會殺死所有的子進程,應用就會退出。那麼有灰色背景的一段代碼就能夠防止在子進程退出時重新啟動。

經測試紅色字體標出的說法是不正確的,如果訪問http://localhost:3000/explode,會引發錯誤,並且cluster會把這個請求傳遞給他所有的子進程,導致所有的子進程都掛掉,並不是一個子進程。

性能測試

當我們使用8核集羣方式進行性能測試,單進程結果如下:

Transactions: 15932 hits Availability: 100.00 % Elapsed time: 19.41 secs Data transferred: 0.18 MB Response time: 0.02 secs Transaction rate: 820.64 trans/sec Throughput: 0.01 MB/sec Concurrency: 14.79 Successful transactions: 15932 Failed transactions: 0 Longest transaction: 0.03 Shortest transaction: 0.01

而啟動了集羣方式的8核性能如下:

Transactions: 34479 hits Availability: 100.00 % Elapsed time: 19.38 secs Data transferred: 0.39 MB Response time: 0.00 secs Transaction rate: 1779.38 trans/sec Throughput: 0.02 MB/sec Concurrency: 7.93 Successful transactions: 34489 Failed transactions: 0 Longest transaction: 0.07 Shortest transaction: 0.00

注意到第一行數據對比,有116%的性能提高。當然Node.js不是CPU-bound重CPU計算的理想選擇,真實世界的結果可能與這個測試有差距,如果你有依賴CPU計算的工作,可使用Node.js作為代理,委託給其他物理機器去執行。

推薦閱讀:

查看原文 >>
相關文章