복붙노트

[MONGODB] MongoDB를 : 끔찍한 맵리 듀스 성능

MONGODB

MongoDB를 : 끔찍한 맵리 듀스 성능

나는 관계형 데이터베이스와 오랜 역사를 가지고,하지만 난 뭔가 잘못된 일을해야 거의 확실 해요, 그래서 나는 MongoDB를하고 맵리 듀스에 새로운 해요. 나는 질문에 권리를 이동합니다. 이 긴 있다면 죄송합니다.

나는 매일 회원 프로필 뷰의 수를 추적 MySQL은 데이터베이스 테이블이있다. 테스트를 위해 그것은 10,000,000 행이 있습니다.

CREATE TABLE `profile_views` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `username` varchar(20) NOT NULL,
  `day` date NOT NULL,
  `views` int(10) unsigned default '0',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `username` (`username`,`day`),
  KEY `day` (`day`)
) ENGINE=InnoDB;

일반적인 데이터는 다음과 같이 있습니다.

+--------+----------+------------+------+
| id     | username | day        | hits |
+--------+----------+------------+------+
| 650001 | Joe      | 2010-07-10 |    1 |
| 650002 | Jane     | 2010-07-10 |    2 |
| 650003 | Jack     | 2010-07-10 |    3 |
| 650004 | Jerry    | 2010-07-10 |    4 |
+--------+----------+------------+------+

나는 2010-07-16 이후 상위 5 가장 많이 본 프로필을 얻기 위해이 쿼리를 사용합니다.

SELECT username, SUM(hits)
FROM profile_views
WHERE day > '2010-07-16'
GROUP BY username
ORDER BY hits DESC
LIMIT 5\G

이 쿼리는 1 분에 완료됩니다. 나쁘지 않다!

이제 MongoDB를 세계에 이동. I 설치 3 개 서버를 사용하여 분산됩니다 환경을 제공합니다. 서버 M, S1 및 S2는. 나는 장비를 설정하려면 다음 명령을 사용 (참고 : 나는 IP의 addys을 가려했습니다).

S1 => 127.20.90.1
./mongod --fork --shardsvr --port 10000 --dbpath=/data/db --logpath=/data/log

S2 => 127.20.90.7
./mongod --fork --shardsvr --port 10000 --dbpath=/data/db --logpath=/data/log

M => 127.20.4.1
./mongod --fork --configsvr --dbpath=/data/db --logpath=/data/log
./mongos --fork --configdb 127.20.4.1 --chunkSize 1 --logpath=/data/slog

그가 있었다 실행되면, 나는 서버 M, 및 발사 몽고에서 뛰어 다녔다. 나는 다음과 같은 명령을 발행 :

use admin
db.runCommand( { addshard : "127.20.90.1:10000", name: "M1" } );
db.runCommand( { addshard : "127.20.90.7:10000", name: "M2" } );
db.runCommand( { enablesharding : "profiles" } );
db.runCommand( { shardcollection : "profiles.views", key : {day : 1} } );
use profiles
db.views.ensureIndex({ hits: -1 });

나는 다음 날 같은 표정을 문서화했다 MySQL의에서 동일한 10,000,000 행을 수입 :

{
    "_id" : ObjectId("4cb8fc285582125055295600"),
    "username" : "Joe",
    "day" : "Fri May 21 2010 00:00:00 GMT-0400 (EDT)",
    "hits" : 16
}

이제 진짜 고기와 여기에 감자 ... 내지도를 제공하고 기능을 줄일 수 있습니다. 위로 쉘 I 설치 쿼리 서버 M에이처럼 실행합니다.

use profiles;
var start = new Date(2010, 7, 16);
var map = function() {
    emit(this.username, this.hits);
}
var reduce = function(key, values) {
    var sum = 0;
    for(var i in values) sum += values[i];
    return sum;
}
res = db.views.mapReduce(
    map,
    reduce,
    {
        query : { day: { $gt: start }}
    }
);

그리고 여기의 나는 문제에 실행했다. 이 쿼리는 전체 15 분 이상 걸렸다! MySQL의 쿼리는 1 분했다. 다음은 출력입니다 :

{
        "result" : "tmp.mr.mapreduce_1287207199_6",
        "shardCounts" : {
                "127.20.90.7:10000" : {
                        "input" : 4917653,
                        "emit" : 4917653,
                        "output" : 1105648
                },
                "127.20.90.1:10000" : {
                        "input" : 5082347,
                        "emit" : 5082347,
                        "output" : 1150547
                }
        },
        "counts" : {
                "emit" : NumberLong(10000000),
                "input" : NumberLong(10000000),
                "output" : NumberLong(2256195)
        },
        "ok" : 1,
        "timeMillis" : 811207,
        "timing" : {
                "shards" : 651467,
                "final" : 159740
        },
}

그것을 실행에 영원히 가지고,하지만 결과도 정확하지 않는 것 않았다뿐만 아니라.

db[res.result].find().sort({ hits: -1 }).limit(5);
{ "_id" : "Joe", "value" : 128 }
{ "_id" : "Jane", "value" : 2 }
{ "_id" : "Jerry", "value" : 2 }
{ "_id" : "Jack", "value" : 2 }
{ "_id" : "Jessy", "value" : 3 }

나는 그 값의 숫자는 훨씬 더 높아야한다 알고있다.

전체 맵리 듀스 패러다임의 나의 이해는 성능을 향상해야 모든 샤드 구성원 사이에 분할해야이 쿼리를 수행하는 작업입니다. 몽고 가져 오기 후 두 파편 서버 사이의 문서를 배포 이루어졌다 때까지 나는 기다렸다. 나는이 쿼리를 시작할 때마다 거의 정확하게 5,000,000 문서를했다.

그래서 내가 뭔가 잘못된 일을해야합니다. 사람이 나에게 어떤 포인터를 줄 수 있습니까?

편집 : IRC에 누군가가 날 필드에 인덱스를 추가 언급하지만, 지금까지의 내가 그것을 말할 수있는 MongoDB에 의해 자동으로 이루어졌다.

해결법

  1. ==============================

    1.오라일리에서 MongoDB의 확실한 가이드에서 발췌 :

    오라일리에서 MongoDB의 확실한 가이드에서 발췌 :

    options for map/reduce:
    
    "keeptemp" : boolean 
    If the temporary result collection should be saved when the connection is closed. 
    
    "output" : string 
    Name for the output collection. Setting this option implies keeptemp : true. 
    
  2. ==============================

    2.어쩌면 내가 너무 늦었 어,하지만 ...

    어쩌면 내가 너무 늦었 어,하지만 ...

    첫째, 당신은 인덱스없이 맵리 듀스를 채우기 위해 컬렉션을 조회한다. 당신은 "일"에 인덱스를 만들어야합니다.

    MongoDB를 맵리 듀스는 단일 서버에서 단일 스레드이지만, 파편에 병렬화. 몽고 파편의 데이터는 함께 연속 청크를 유지 키를 샤딩으로 분류되어 있습니다.

    당신의 샤딩 키 "일", 그리고 당신이 그것에 쿼리하는 것처럼, 당신은 아마에만 세 개의 서버 중 하나를 사용하고 있습니다. 키를 샤딩하는 데이터 만 확산하는 데 사용됩니다. 각 파편의 "일"인덱스를 사용하여 쿼리합니다 절감지도, 매우 빠른 것입니다.

    데이터를 확산하기 위해 하루 키의 앞에 무언가를 추가합니다. 사용자 이름은 좋은 선택이 될 수 있습니다.

    지도가 감소 그런 식으로 모든 서버에서 시작 잘하면 세에 의해 시간을 단축됩니다.

    이 같은:

    use admin
    db.runCommand( { addshard : "127.20.90.1:10000", name: "M1" } );
    db.runCommand( { addshard : "127.20.90.7:10000", name: "M2" } );
    db.runCommand( { enablesharding : "profiles" } );
    db.runCommand( { shardcollection : "profiles.views", key : {username : 1,day: 1} } );
    use profiles
    db.views.ensureIndex({ hits: -1 });
    db.views.ensureIndex({ day: -1 });
    

    나는 더 빨리, 그 추가와 함께, 당신은 MySQL의 속도를 일치 수 있다고 생각합니다.

    또한, 더 나은 실시간으로 사용하지 마십시오. 데이터가 "미세"정확하게 할 필요가없는 경우, 이제지도 감소 작업마다를 shedule 및 결과 수집을 사용합니다.

  3. ==============================

    3.당신은 아무것도 잘못을하고 있지 않습니다. (당신은 이미 귀하의 의견에 눈치 잘못된 값에 정렬 게다가.)

    당신은 아무것도 잘못을하고 있지 않습니다. (당신은 이미 귀하의 의견에 눈치 잘못된 값에 정렬 게다가.)

    MongoDB를 단지 좋은 것이 아니다 성능이 저하 / 매핑합니다. 이것은 알려진 문제입니다; 순진 접근 방식은 빠른 M / R 이상 ~ 350x입니다 예를 http://jira.mongodb.org/browse/SERVER-1197를 참조하십시오.

    하지만 장점 중 하나는 당신이 맵리 듀스 호출의 아웃 인수와 함께 영구적 인 출력 컬렉션 이름을 지정할 수 있다는 것입니다. 는 M / R이 완료되면 임시 컬렉션 원자 영구 이름으로 이름이 변경됩니다. 그런 식으로 당신은 당신의 통계 업데이트를 예약하고, M / R 출력 컬렉션을 실시간으로 조회 할 수 있습니다.

  4. ==============================

    4.당신은 이미 MongoDB를위한 하둡 커넥터를 사용하여 시도 적이 있습니까?

    당신은 이미 MongoDB를위한 하둡 커넥터를 사용하여 시도 적이 있습니까?

    여기 링크에서 봐 : http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-hadoop/

    만 3 파편을 사용하고 있기 때문에,이 방법은 당신의 사건을 향상시킬 것입니다 여부를 알 수 없습니다.

  5. from https://stackoverflow.com/questions/3947889/mongodb-terrible-mapreduce-performance by cc-by-sa and MIT license