2010/11/02 20:14
※ 아래의 성능 테스팅 결과는 100%신뢰하지 마세요.. Rough하게 테스팅했을 때에도 충분히 어느정도의 성능을 내주는 솔루션이 좋은 솔루션일 수 있습니다만, 아래의 테스트는 초기에 MongoDB의 특징을 제대로 간파하지 못한 상태로 테스팅한 결과라 정확하지 않습니다. 새롭게 테스트한 결과를 업데이트 해야하는데, 게을러서 못하고 있네요..서둘러 하도록 하겠습니다..ㅠ_ㅠ
이번에 MongoDB에 대한 성능을 Rough하게 테스트를 해보고자 했다. 서비스에 투입시키기 위해서 선행되어야 할 몇가지 테스팅 항목들을 결정하였는데 그 항목들은 아래와 같다.
1. Connection Test
2. SELECT/DELETE/UPDATE/WRITE Performance Test
3. Replica/Shading 구조에서 Master장애 발생시 MongoDB의 동작 방식 및 대응방법
일단 가장 단순하면서도 쉽게 해볼 수 있는 SELECT/DELETE/UPDATE/WRITE Performance Test를 해보려고 했다. 테스트 환경은 RHEL4 32bit의 서버에서 수행하였으며, 실험과정은 아주 단순하게 1,000,000건을 Insert한 후, 차례차례 findOne()메소드를 이용하여 각 Document의 Unique Key를 Query에 추가하여 모두 한건씩 Select한 후, Insert했던 모든 Data를 삭제하는 과정으로 이루어졌다. 실험과정에서 각각 insert, select, delete에 시간이 얼마나 소요되는지 측정하였으며, 이러한 연산과정을 총 10번씩 반복하였다. 먼저 INSERT성능 테스트 코드는 아래와 같다.
System.out.println("===========" + j +"번째 Insert 시작============");
start = System.currentTimeMillis();
for (int i = 0; i < settingRows; i++) {
String dummy = String.valueOf(i);
BasicDBObject doc = new BasicDBObject();
doc.put("id", "12345" + dummy);
doc.put("date", new Date());
col.insert(doc);
}
end = System.currentTimeMillis();
System.out.println(settingRows + "건 Insert 완료");
System.out.println( "실행 시간 : " + ( end - start )/1000.0 + "sec" );
System.out.println();
위와 같이 INSERT를 수행하면서 mongodb에서 제공하는 모니터링 툴인 mongostat을 이용하여 모니터링한 결과는 아래 그림과 같다.
INSERT의 결과는 비교적 나쁘지 않았다. 초당 평균 5000~6000정도의 qps를 보임으로 인해 실서비스에서도 어느정도 많은 데이터 유입을 감당해 낼 수 있을 것 같았다.
다음은 SELECT연산인데 SELECT 성능 테스트 코드는 아래의 형태와 같다.
System.out.println("===========" + j +"번째 Select 시작============");
start = System.currentTimeMillis();
for (int i = 0; i < settingRows; i++) {
String dummy = String.valueOf(i);
BasicDBObject query = new BasicDBObject();
query.put("id", "12345" + dummy);
col.findOne(query);
}
end = System.currentTimeMillis();
System.out.println(settingRows + "건 Select 완료");
System.out.println( "실행 시간 : " + ( end - start )/1000.0 + "sec");
System.out.println();
이렇게 SELECT하는 동안의 mongostat의 모니터링 결과는 아래와 같다.
생각외로 굉장히 느린 qps를 보여주고 있었다. INSERT에서는 이정도까지는 아니었는데, 오히려 SELECT연산에서 너무 느린 성능을 보여주고 있었다. 아마 File Base형태의 DB이기에 File을 일일히 찾아야 하기 때문인 것 같은데, 그렇다 치더라도 이러한 속도를 보여주는 것은 실 서비스에서는 도저히 감당이 되지 않을 속도였다.
이러한 문제를 해결해보고자 다시 데이터를 다 삭제한 후, 데이터를 INSERT하기 전에 먼저 id컬럼에 Index를 생성한 뒤 다시 INSERT와 SELECT를 위와 동일한 코드로 실험을 실행해 보았고 그 결과는 아래와 같다.
Insert with Index
실험결과를 보았을때 Index를 걸어줬을때가 그렇지 않은 경우보다 더 높은 qps를 보여주는 것을 알 수 있었다. 아주 비약적인 속도의 성장세를 보여준 것은 아니지만 약 5000~6000대에서 7000~75000정도로 상승된 qps를 보여주는 것만으로도 충분히 만족스러웠다.
Select with Index
역시 Index를 걸어주기 전보다 더 나은 성능을 보여주고 있는 것을 알 수 있었다. 하지만 역시나 원체 느린 qps를 보여주고 있었기에 더 나은 성능을 보인다 하더라도 너무 느린 결과를 보여주고 있었다. File Base의 특징상 Disk의 I/O 속도에도 굉장히 영향을 많이 받을 것이고, 또한 이러한 실험이 애초에 접근방식이 잘못된 것일 수도 있기때문에 뭐라 단정짓긴 힘들지만, (실제로 회사내 다른 팀에서 고성능 서버에서 테스트한 64비트 mongodb에서는 1,000,000건을 SELECT하는데 약 12초가 안걸리는 실험 결과를 얻기도 했다) 어쨌던 SELECT 연산은 NoSQL의 명성에 안맞게 생각보다 너무 조악했다.
마지막으로 Index가 걸린 상태에서 DELETE연산을 수행하였으며 그 코드는 아래와 같다.
System.out.println("===========" + j +"번째 Delete 시작============");
start = System.currentTimeMillis();
for (int i = 0; i < settingRows; i++) {
String dummy = String.valueOf(i);
BasicDBObject query = new BasicDBObject();
query.put("id", "12345" + dummy);
col.remove(query);
}
end = System.currentTimeMillis();
System.out.println(settingRows + "건 Delete 완료");
System.out.println( "실행 시간 : " + ( end - start )/1000.0 + "sec");
System.out.println();
DELETE하는 동안의 mongostat을 이용한 모니터링 결과는 아래와 같다.
DELETE하는 동안 qps는 오히려 INSERT보다 더 나은 수치를 보였으며 거의 INSERT와 비슷한 만족스런 성능을 보여주고 있었다. 아마 index를 걸지 않고 DELETE를 했었어도 INSERT때와 마찬가지로 큰 성능의 저하는 없었을 것 같다.
이러한 실험이 10번 반복되는 동안 각각의 연산 수행시간 기록은 아래와 같다.
===========0번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 137.132sec
===========0번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 130.344sec
===========1번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 137.65sec
===========1번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 128.478sec
===========2번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 140.366sec
===========2번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 131.829sec
===========3번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 141.41sec
===========3번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 129.007sec
===========4번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 140.408sec
===========4번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 131.5sec
===========5번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 143.558sec
===========5번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 130.563sec
===========6번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 143.754sec
===========6번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 130.246sec
===========7번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 140.479sec
===========7번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 129.211sec
===========8번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 142.175sec
===========8번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 131.343sec
===========9번째 Insert 시작============
1000000건 Insert 완료
실행 시간 : 142.196sec
===========9번째 Delete 시작============
1000000건 Delete 완료
실행 시간 : 128.106sec
SELECT연산의 경우 너무 느려서 결국 실제 성능 측정 실험에서는 주석처리하여 수행하지 않고 오로지 INSERT와 DELETE에 대해서만 수행시간을 측정해 보았다. 전체적으로 약 1,000,000건의 INSERT와 DELETE연산에 대해 약 2분 조금 넘는 시간을 보였으며 비교적 만족스러운 결과를 얻을 수 있었다. 이전에도 말했던 것처럼 Disk의 성능이 높아지면 높아질 수록 수행시간도 단축되는 결과를 얻을 수 있을 것 같다.
이러한 실험결과는 처음에도 말했던 것과 같이 매우 rough한 실험이었으며 그 실험과정이나 조건들이 100% 정확한 상태에서 혹은 적합한 상태인지 모르는 상황에서 수행한 것으로 100%신뢰하기에는 어려움이 있을 것 같다. 하지만 전반적인 추정은 가능할 것으로 보이며, 특히 SELECT의 경우에는 좀 더 다양한 조건에서 여러번 실험을 더욱 수행해볼 필요는 있을 것 같다. 테스트에 사용한 코드를 첨부하니 직접 테스트하길 원하시는 분들은 받아서 해보시길..
'Programming > NoSQL' 카테고리의 다른 글
| MongoDB 적용사례 (0) | 2011/07/13 |
|---|---|
| NoSQL에 대한 고찰 (15) | 2010/11/30 |
| MongoDB 성능 테스팅 (2) | 2010/11/02 |
| MongoDB Java Driver에서 IN Query사용하기 (0) | 2010/11/02 |
| MongoDB Select 예제 (0) | 2010/10/26 |
| NoSQL 관련 문서 (0) | 2010/10/26 |
TAG MongoDB,
MongoDB 성능테스트
test.java