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 は細かい制御は難しい(カーネルによるロードバランシング)ですが、簡単にスケールできて便利