MongoDB: 끔찍한 맵성능 저하
저는 관계형 데이터베이스에 대한 오랜 역사를 가지고 있지만, MongoDB와 MapReduce는 처음이라 제가 뭔가 잘못하고 있는 것이 틀림없다고 거의 확신합니다.바로 질문으로 넘어가겠습니다.길면 죄송합니다.
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의 세계로 이동합니다.나는 3대의 서버를 사용하여 샤드 환경을 설정했습니다.서버 M, S1 및 S2.다음 명령을 사용하여 리그를 설정했습니다(참고:IP 주소를 숨겼습니다.
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 서버에 올라 mongo를 시작했습니다.저는 다음과 같은 명령을 내렸습니다.
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
}
이제 진짜 고기와 감자가 여기에 옵니다.나의 지도와 기능 축소.셸의 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 }
저는 그 수치들이 훨씬 더 높아야 한다는 것을 알고 있습니다.
전체 MapReduce 패러다임에 대한 제 이해는 이 쿼리를 수행하는 작업이 모든 샤드 멤버로 분할되어 성능이 향상되어야 한다는 것입니다.나는 Mongo가 가져오기 후 두 샤드 서버 간에 문서 배포가 끝날 때까지 기다렸습니다.제가 이 질문을 시작했을 때, 각각은 거의 정확히 5,000,000개의 문서를 가지고 있었습니다.
그래서 제가 뭔가 잘못하고 있는 게 분명해요.누가 나에게 조언을 해줄 수 있습니까?
편집: IRC의 누군가가 day 필드에 인덱스를 추가하는 것을 언급했지만, 제가 알기로는 MongoDB에 의해 자동으로 수행되었습니다.
O'Reilly의 MongoDB Definitional Guide에서 발췌:
MapReduce를 사용하는 데 드는 비용은 속도입니다. 그룹은 특별히 빠르지 않지만 MapReduce는 더 느리고 "실시간"에 사용할 수 없습니다.MapReduce를 백그라운드 작업으로 실행하면 결과 모음이 생성되고 실시간으로 해당 컬렉션을 쿼리할 수 있습니다.
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.
내가 너무 늦었는지도 모르지만,
먼저 인덱스 없이 MapReduce를 채우기 위해 컬렉션을 쿼리합니다."요일"에 인덱스를 생성해야 합니다.
MongoDB MapReduce는 단일 서버에서 단일 스레드이지만 샤드에서 병렬 처리됩니다.몽고 하드의 데이터는 샤딩 키별로 정렬된 연속 청크로 함께 보관됩니다.
샤딩 키가 "day"이고 쿼리 중이므로 세 개의 서버 중 하나만 사용할 수 있습니다.샤딩 키는 데이터를 분산하는 데만 사용됩니다.맵 축소는 각 샤드의 "일" 인덱스를 사용하여 쿼리하며 매우 빠릅니다.
데이 키 앞에 데이터를 펼치기 위해 무언가를 추가합니다.사용자 이름은 좋은 선택이 될 수 있습니다.
이렇게 하면 모든 서버에서 맵 축소가 시작되고 시간이 3시간 단축될 것입니다.
이와 같은 것:
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 속도를 더욱 빠르게 맞출 수 있습니다.
또한 실시간으로 사용하지 않는 것이 좋습니다.데이터를 "분 단위"로 정확하게 작성할 필요가 없는 경우에는 지도 축소 작업을 항상 예약하고 결과 수집을 사용합니다.
당신은 잘못된 행동을 하고 있지 않습니다. (댓글에서 이미 알아차린 것처럼 잘못된 값으로 정렬하는 것 외에도)
MongoDB 맵/성능 감소는 그다지 좋지 않습니다.이것은 알려진 문제입니다. 예를 들어, M/R보다 350배 빠른 순진한 접근 방식의 http://jira.mongodb.org/browse/SERVER-1197 을 참조하십시오.
그러나 한 가지 장점은 영구적인 출력 수집 이름을 지정할 수 있다는 것입니다.out
의 주장mapReduce
M/R이 완료되면 임시 컬렉션의 이름이 영구 이름으로 자동 변경됩니다.그러면 통계 업데이트를 예약하고 실시간으로 M/R 출력 수집을 쿼리할 수 있습니다.
mongodb에 hadoop 커넥터를 사용해 본 적이 있습니까?
다음 링크를 참조하십시오. http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-hadoop/
당신은 3개의 샤드만 사용하고 있기 때문에 이 방법이 당신의 사례를 개선할 수 있을지 모르겠습니다.
언급URL : https://stackoverflow.com/questions/3947889/mongodb-terrible-mapreduce-performance
'source' 카테고리의 다른 글
깃 상위 포인터를 다른 상위 포인터로 설정 (0) | 2023.05.01 |
---|---|
WPF 데이터 그리드 선택 행 클릭 이벤트? (0) | 2023.05.01 |
WPF 콤보 상자 디스플레이 구성원 경로 (0) | 2023.05.01 |
IIS 7.5의 ASP.NET MVC - 오류 403.14 금지 (0) | 2023.05.01 |
Visual Studio Code에서 실행 중인 Angular 응용 프로그램에서 TSLint 확장자 쓰기 오류 발생 (0) | 2023.04.26 |