集羣clusterfork運行Node.js
集羣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作為代理,委託給其他物理機器去執行。
推薦閱讀: