2013-06-11 1 views
5

은 내가 분산됩니다 클러스터에서 mongos 인스턴스에 대해 큰 컬렉션 중복 감지 맵리 듀스 작업을 실행하는거야 내가 운전 10 분 이상 걸릴 것으로 예상 :장기간에 걸친 mapreduce 조작에서 커서 시간 종료를 피하려면 어떻게합니까?

m = function() { 
    emit(this.fieldForDupCheck, 1); 
} 
r = function (k, vals) { 
    return Array.sum(vals); 
} 
res = db.Collection.mapReduce(m, r, { out : "dups" }); 

를이 나에게 다음과 같은 오류를 제공 실행 처리 10 분 :

uncaught exception: map reduce failed:{ 
"ok" : 0, 
"errmsg" : "MR post processing failed: { result: "dups", errmsg: "exception: getMore: cursor didn't exist on server, possible restart or timeout?", code: 13127, ok: 0.0 }" 
} 
제가 MapReduce의 호출에 .addOption(DBQuery.Option.noTimeout)를 사용하여 adding a noTimeout option 시도

있지만 쉘의 JS 에러 결과 Object [object Object] has no method 'addOption'

,

장기간에 걸친 mapreduce 작업에서 커서 시간 제한을 피하는 방법은 무엇입니까?

답변

6

사용중인 MongoDB의 릴리스는 언급하지 않았지만 해결책은 여기에 제시된 것과 유사합니다. Ubuntu 13.04와 함께 제공되는 2.2.4를 설명합니다.

실제로이 문제는 커서에 옵션을 삽입하는 문제입니다. 그건 어디 addOption 삶 :

> var cursor = db.test.find() 
> cursor.addOption 
function (option) { 
    this._options |= option; 
    return this; 
} 

이의이 mapReduce 정의하는 방법을 살펴 보자 :

> db.test.mapReduce 
function (map, reduce, optionsOrOutString) { 
    var c = {mapreduce:this._shortName, map:map, reduce:reduce}; 
    ... 
    var raw = this._db.runCommand(c); 
    ... 
    return new MapReduceResult(this._db, raw); 
} 

는 그래서 runCommand를 통해 명령을 실행하는 문서를 작성합니다. 더 자세히 살펴 보겠습니다.

> db.runCommand 
function (obj) { 
    if (typeof obj == "string") { 
     var n = {}; 
     n[obj] = 1; 
     obj = n; 
    } 
    return this.getCollection("$cmd").findOne(obj); 
} 

따라서 명령은 findOne을 통해 실행됩니다. 살펴보기 :

> db.test.findOne 
function (query, fields, options) { 
    var cursor = this._mongo.find(this._fullName, this._massageObject(query) || {}, fields, -1, 0, 0, options || this.getQueryOptions()); 
    if (!cursor.hasNext()) { 
     return null; 
    } 
    var ret = cursor.next(); 
    ... 
    return ret; 
} 

아, 여기 흥미로운 것이 있습니다. 커서는 매개 변수 options에서 오는 플래그로 초기화되는데, 이는 불행히도 runCommand이 설정되지 않기 때문에 불행히도 도움이되지 않지만 컬렉션에서 오는 getQueryOptions()과 OR됩니다. 조사해 보겠습니다.

> db.collection.getQueryOptions 
function() { 
    var options = 0; 
    if (this.getSlaveOk()) { 
     options |= 4; 
    } 
    return options; 
} 

죄송합니다. 괜찮습니다. 따라서 우리는 커서에 접근 할 수 없으며 비 hackish 수단을 통해 실행 된 명령에 쿼리 옵션을 삽입 할 수 없습니다.

글쎄, 맵 축소 명령이 실제로 그 프로세스를 통해 서버에 전달되는 방법에 대해 많은 것을 배웠습니다. 데이터베이스의 특정 컬렉션에 대해 쿼리되는 문서 일뿐입니다. 즉, 동일한 쿼리를 작성하여 직접 실행할 수 있지만 필요한 플래그를 제공 할 수 있습니다.

전체 MongoDB 명령을 작성하고 결과를 설정하는 데 어려움은 없지만 실제로는 isMaster 명령을 사용하여 실제로 작동하는지 보여 드리겠습니다.

어떤 플래그없이 실행되는 명령입니다

> db.getCollection("$cmd").findOne({isMaster: 1}).ismaster 
true 

효과의 차이를 보려면, 우리는 데이터베이스와의 통신 tcpdump을 것입니다.우리는 관련 플래그 정수 32 비트, 바로 컬렉션 이름 앞에 살고 the wire protocol documentation에서 볼 수있는, 그래서 덤프의 관련 부분 발견하기 쉽습니다 :

.     vvvvvvvvv 
    0x0040: d407 0000 0000 0000 7465 7374 2e24 636d ........test.$cm 
    0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i 

좋음. 컬렉션 이름 바로 앞에 4 바이트가 0으로 표시됩니다.

이제 플래그를 제공하면서 동일한 작업을 수행해 보겠습니다. 우리는 쿼리 플래그 findOne의 세 번째 옵션으로 제공 될 수 위의 디버깅 섹션에서 배운, 그래서 그렇게 할 수 있도록했습니다 덤프

> db.getCollection("$cmd").findOne({isMaster: 1}, undefined, 0xBEEF).ismaster 
true 

을 볼 : 이봐,

.     vvvvvvvvv 
    0x0040: d407 0000 efbe 0000 7465 7374 2e24 636d ........test.$cm 
    0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i 

우리 플래그가 전달되어야하고, 반전 된 것을 볼 수 있습니다. 즉, 바이트가 리틀 엔디안으로 인코딩되고 the docs과 일치 함을 의미합니다. 그래서

, 즉 우리가 isMaster했던 것과 유사한 방법으로 in the documentation 설명 된대로 세 번째 findOne의 옵션, 손으로 코드로지도-감소 명령을 플래그 DBQuery.Option.noTimeout를 제공 할 수 있다는 것을 의미합니다, 당신은 무엇을 얻을 것이다 네가 원해.

관련 문제