MongoDB で Node.js のパフォーマンスをテストしています。これらのそれぞれが他とは無関係に問題ないことはわかっていますが、いくつかのテストを試して感触をつかもうとしています。この問題に遭遇しましたが、ソースを特定するのに苦労しています。
問題
1 つの Node.js プログラムに 1,000,000 レコードを挿入しようとしています。 絶対に這う。 実行時間は 20 分です。これは、Mac と CentOS のどちらでも発生しますが、両者の動作はわずかに異なります。それは最終的に完了します。
効果はスワッピングに似ていますが、そうではありません (メモリが 2 GB を超えることはありません)。MongoDB に対して開かれている接続は 3 つだけで、ほとんどの場合、データが挿入されていません。多くのコンテキスト切り替えを行っているようで、Node.js の CPU コアが使い果たされています。
効果は、このスレッドで言及されているものと似ています。
PHPを使用して同じことを試してみると、2〜3分で終了します。ドラマはありません。
なんで?
考えられる原因
私は現在、これが Node.js ソケットの問題、舞台裏で libev で起こっていること、またはその他の node-mongodb-native の問題であると考えています。私は完全に間違っているかもしれないので、ここで少しガイダンスを探しています。
他の Node.js MongoDB アダプターについては、Mongolian を試してみましたが、ドキュメントをバッチ挿入するためにドキュメントをキューに入れているように見え、最終的にメモリ不足になります。それで終わりです。(補足: 16 GB のボックス制限にさえ近づいていないため、これについても理由はわかりませんが、それ以上の調査は行っていません。)
実際、(クアッドコア マシン上で) 4 つのワーカーを使用してマスター/ワーカー クラスターをテストしたところ、2 ~ 3 分で完了したことを言及しておく必要があります。
コード
これが私の Node.js CoffeeScript プログラムです。
mongodb = require "mongodb"
microtime = require "microtime"
crypto = require "crypto"
times = 1000000
server = new mongodb.Server "127.0.0.1", 27017
db = mongodb.Db "test", server
db.open (error, client) ->
throw error if error?
collection = mongodb.Collection client, "foo"
for i in [0...times]
console.log "Inserting #{i}..." if i % 100000 == 0
hash = crypto.createHash "sha1"
hash.update "" + microtime.now() + (Math.random() * 255 | 0)
key = hash.digest "hex"
doc =
key: key,
foo1: 1000,
foo2: 1000,
foo3: 1000,
bar1: 2000,
bar2: 2000,
bar3: 2000,
baz1: 3000,
baz2: 3000,
baz3: 3000
collection.insert doc, safe: true, (error, response) ->
console.log error.message if error
これとほぼ同等の PHP プログラムを次に示します。
<?php
$mongo = new Mongo();
$collection = $mongo->test->foo;
$times = 1000000;
for ($i = 0; $i < $times; $i++) {
if ($i % 100000 == 0) {
print "Inserting $i...\n";
}
$doc = array(
"key" => sha1(microtime(true) + rand(0, 255)),
"foo1" => 1000,
"foo2" => 1000,
"foo3" => 1000,
"bar1" => 2000,
"bar2" => 2000,
"bar3" => 2000,
"baz1" => 3000,
"baz2" => 3000,
"baz3" => 3000
);
try {
$collection->insert($doc, array("safe" => true));
} catch (MongoCursorException $e) {
print $e->getMessage() . "\n";
}
}