Node.js の Cluster のベンチマークをとってみた
Node.js v0.6 から新規標準モジュールとして導入された Cluster のベンチマークを取ってみました。
測定環境
Server
CPU: AMD PhenomII X6 1090T (6コア) MEM: DDR3 16GB (4GB*4)
Client
MacBook Pro 15 (Early 2011) CPU: Intel Core i7 2.0GHz (4コア) MEM: DDR3 8GB (4GB*2)
Network
1GigabitEther (同一セグメント)
テスト方法
テストスクリプト
cluster-bench.js
var cluster = require('cluster');
var http = require('http');
var numCPUs = parseInt(process.argv[2], 10);
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('death', function(worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
// Worker processes have a http server.
http.createServer(function(req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
測定方法
ワーカを必要な数だけ起動
node cluster-bench.js n # nはワーカ数
その後、ApacheBench を5回実行し、その平均値を取る。
ab -n 10000 -c 200 http://servername:8000/
結果
コア数以上のワーカを起動した場合(n=7,8)も測ってみた。
表
(単位: requests/sec)
| n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 1回目 | 7380.28 | 14737.7 | 17161.38 | 17480.74 | 17621.82 | 17900.07 | 17543.07 | 17806.95 |
| 2回目 | 7039.88 | 14704.28 | 17100.9 | 17549.85 | 17930.77 | 17709.73 | 17491.9 | 17733 |
| 3回目 | 7479.57 | 14555.54 | 17205.59 | 17420.46 | 17605.32 | 17598.3 | 17327.33 | 17849.72 |
| 4回目 | 7553.31 | 14759.31 | 17248.57 | 17451.11 | 17667.13 | 18138.7 | 17820.31 | 17710.82 |
| 5回目 | 7360.04 | 14670.48 | 17269.42 | 17378.11 | 17060.33 | 17818.24 | 17699.15 | 17767.5 |
| 平均 | 7362.616 | 14685.462 | 17197.172 | 17456.054 | 17577.074 | 17833.008 | 17576.352 | 17773.598 |
考察
ここまででわかること。
・ワーカ数に応じたスループットの向上は実現できている
・ワーカ数が3以上はほぼ頭打ち(緩やかには伸びているので、クラスタの効果は出ているはず)
・17,000 req/sec あたりで頭打ちになっているのはベンチマーク環境の限界か?
どうやら処理が軽すぎると、ネットワークなど他の部分がネックになって、頭打ちになるようなので、意図的にCPUピーキーな処理をやってみた。
なにかと話題のフィボナッチ数列の計算で、CPUが90%付近に張り付くように再帰の回数を設定。
テストスクリプト(CPUピーキー版)
ar cluster = require('cluster');
var http = require('http');
var numCPUs = parseInt(process.argv[2], 10);
function fib(i) {
if(i == 0 || i == 1) return i;
return fib(i-1) + fib(i-2);
}
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('death', function(worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
// Worker processes have a http server.
http.Server(function(req, res) {
res.writeHead(200);
fib(20);
res.end("hello world\n");
}).listen(8000);
}
なんとなく思ったこと
・軽い処理の場合は、Nodeが速すぎて他の部分がネックになるので、ワーカ数はその辺りで調整すればよい
・重い処理がある場合、コアを目一杯使うと綺麗にスケールする
・Node.js の Cluster は細かい制御は難しい(カーネルによるロードバランシング)ですが、簡単にスケールできて便利

