2012-06-20 2 views
3

Node.js의 성능을 MongoDB에서 테스트하고 있습니다. 나는 이것들 각각이 다른 것과 독립적으로 독립적이라는 것을 알지만, 나는 그들에 대한 느낌을 얻기 위해 소수의 테스트를 시도하고있다. 나는이 문제를 겪었고 소스를 결정하는 데 문제가있다.node-mongodb-native의 성능을 삽입하십시오.

나는 하나의 Node.js를 프로그램에서 1,000,000 레코드를 삽입하기 위해 노력하고있어

문제점. 절대적으로 크롤링합니다. 우리는 20 분의 실행 시간을 말하고 있습니다. 이것은 Mac이나 CentOS 이건간에 발생합니다. 그것은 결국 완료됩니다.

효과는 스와핑과 비슷하지만 메모리는 2GB를 넘지 않습니다. MongoDB에는 3 개의 연결 만 열려 있으며 대부분의 경우 데이터가 삽입되지 않습니다. 많은 컨텍스트 스위칭을 수행하는 것으로 보입니다. Node.js CPU 코어는 최대치입니다.

효과는 this thread에서 언급 한 것과 유사합니다.

나는 PHP를 사용하여 같은 것을 시도하고 2 ~ 3 분 내에 완료된다. 드라마가 없습니다.

왜? 가능한

나는 현재이는 Node.js를 소켓 문제, 뒤에서 libev로 계속 뭔가, 또는 다른 노드 MongoDB의 네이티브 문제 중 하나라고 생각하도록합니다. 나는 완전히 틀릴지도 모른다. 그래서 나는 약간의 지침을 찾고있다.

다른 Node.js MongoDB 어댑터에 대해서는 몽골어를 사용해 보았습니다. 배치를 삽입하기 위해 문서를 큐에 넣은 것처럼 보이며 메모리가 부족한 상태로 끝납니다. 그게 다야. (사이드 노트 : 16 GB 박스 제한에 근접하지도 않았으므로이 점도 이해할 수 없다.하지만 그것에 대해서는 더 이상 조사하지 않았다.)

나는 아마도 내가 실제로 쿼터 코어 머신에서 4 명의 작업자가있는 마스터/작업자 클러스터를 테스트했음을 언급하고 2 ~ 3 분만에 마쳤습니다.

강령

은 여기 내 Node.js를 커피 스크립트 프로그램입니다 :

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"; 
    } 
} 
+0

글쎄, 공정하게 당신은 내 사용 사례를 정말로 모른다. 이것은 단지 하나의 테스트 일뿐입니다. 흥미로운 결과를 얻었고 Node.js 전체 또는 특정 모듈에 적용했는지 궁금합니다. 어쨌든 원인을 이해하면 Node.js 및/또는이 모듈을보다 효과적으로 사용하는 방법을 더 잘 이해할 수 있습니다. :-) –

+0

사실은 클라이언트 라이브러리 일 수도 있습니다. – hakre

+0

node.js CPU 코어가 초과 된 경우 이미 문제를 발견하지 못했습니다. 모든 단일 프로세스 JS 기반 애플리케이션 서버는 최대 처리량에 가까운 것을 달성하지 못합니다. 같은 상자에서 여러 node.js 프로세스를 시작하면 어떻게됩니까? 솔직하게 말해서 나는 node.js가 웹 애플 리케이션 개발 스펙트럼의 더 전문적인 끝에 왜 이런 종류의 이유가 있지만 어째서 왜 그런지에 대해 완전히 신비 스럽다. –

답변

2

V8에서 기본 힙 한계를 실행하는 것처럼 들립니다. 이 제한을 제거하는 방법에 대해 blog post이라고 적었습니다.

가비지 컬렉터는 아마도 CPU를 미친 듯이 움직이고 있습니다. 1.4GB 한도 이하가 될 때까지 계속 실행되기 때문입니다.

+0

완벽한, 이것이 내가 찾고있는 대답이다. On Node.js 0.8.0'node --trace-gc' (이 옵션을 발견 한 후)를 실행하여 특정 지점에 도달하면 끊임없이 마킹 속도를 1000 (아마도 하드 코드 된 최대 값) . 물론 그것은 뒤 떨어지는 것을 계속하기 때문에 다시 마킹 속도를 높이려고합니다. 결국 마침내 천천히 다시 스윕을 시작합니다. –

1

명시 적으로 값을 반환하면 어떻게됩니까 db.open 콜백 함수의 끝에서? 귀하의 생성 된 자바 스크립트 코드는 귀하의 모든 collection.insert 리턴을 큰 "_results"배열로 푸시합니다.이 배열은 느리고 느려질 것입니다.

collection.insert doc, safe: true, (error, response) -> 
     console.log error.message if error 

    return 

* 업데이트 :

db.open(function(error, client) { 
    var collection, doc, hash, i, key, _i, _results; 
    if (error != null) { 
    throw error; 
    } 
    collection = mongodb.Collection(client, "foo"); 
    _results = []; 
    for (i = _i = 0; 0 <= times ? _i < times : _i > times; i = 0 <= times ? ++_i : --_i) { 
    ... 
    _results.push(collection.insert(doc, { 
     safe: true 
    }, function(error, response) { 
     if (error) { 
     return console.log(error.message); 
     } 
    })); 
    } 
    return _results; 
}); 

에 한번 당신의 커피 스크립트의 끝 부분이 추가 * 그래서, 실제로 프로그램을 실행했는데, 몇 가지 더 문제 발견 :

가장 큰 문제는 동기식 방식으로 수백만 개의 삽입물을 생성하려고 시도하는 것이므로 RAM을 실제로 없애고 결국 삽입을 중단합니다 (최소한 나에게 도움이되었습니다). 나는 그것을 800MB RAM 정도에서 죽였다.

비동기 적으로 작동하도록 collection.insert()를 호출하는 방식을 변경해야합니다.

mongodb = require "mongodb" 
microtime = require "microtime" 
crypto = require "crypto" 

gen =() -> 
    hash = crypto.createHash "sha1" 
    hash.update "" + microtime.now() + (Math.random() * 255 | 0) 
    key = hash.digest "hex" 

    key: key, 
    foo1: 1000, 
    foo2: 1000, 
    foo3: 1000, 
    bar1: 2000, 
    bar2: 2000, 
    bar3: 2000, 
    baz1: 3000, 
    baz2: 3000, 
    baz3: 3000 

times = 1000000 
i = times 

insertDocs = (collection) -> 
    collection.insert gen(), {safe:true},() -> 
    console.log "Inserting #{times-i}..." if i % 100000 == 0 
    if --i > 0 
     insertDocs(collection) 
    else 
     process.exit 0 
    return 

server = new mongodb.Server "127.0.0.1", 27017 
db = mongodb.Db "test", server 
db.open (error, db) -> 
    throw error if error? 
    db.collection "foo", (err, collection) -> 
    insertDocs(collection) 
    return 
    return 

~ 3 분 안에 완료 :

내가 명확성을 위해 기능 몇 가지를 깨는, 그래서처럼 다시 썼다 또한

wfreeman$ time coffee mongotest.coffee 
Inserting 0... 
Inserting 100000... 
Inserting 200000... 
Inserting 300000... 
Inserting 400000... 
Inserting 500000... 
Inserting 600000... 
Inserting 700000... 
Inserting 800000... 
Inserting 900000... 

real 3m31.991s 
user 1m55.211s 
sys 0m23.420s 

, 그것은 <을 사용하는 부수적 인 이점이있다 100MB RAM, 노드에서 70 % CPU 및 mongod에서 40 % CPU (2 코어 상자에서 CPU를 최대화하지 않는 것처럼 보입니다).

+0

좋은 캐치이며 프로그램 수명의 일부로 약 150MB의 메모리 사용량을 줄이지 만 불행하게도 문제는 메모리가 아닙니다. 여전히 CoffeeScript로 개발하고 큰 세트로 작업 할 때는 명심해야 할 점이 분명합니다. –

+0

속도도 빨라야합니다. 아니? –

+0

아니오 - 메모리 바운드가 아닌 CPU 바운드입니다. 메모리는이 경우 프로세스에 영향을 미치지 않습니다. –

관련 문제