3. 누구?
넥슨에서 10년
2003: 세강 빌딩에서 사회 생활을 시작함
2005~2007: 잠깐 도쿄에서 외국인 노동자 생활을 경험함
2007~2013: 다시 선릉역으로 출퇴근
Spearhead Studio 2년
2013.5~: FIFA실 Software Engineer
서버 운영, DB, 툴 유지보수, 모니터링 등등…
잡캐
이런저런 것 다 좋아하고, 먹고 살려면 다 하게 됩디다
3
5. 일러두기
여기서 다루는 MongoDB 2.2, 2.4는 오래된 버전입니다
최신 버전에서는 해결된 문제가 좀 있습니다
생각보다 기본적인 내용일 수 있습니다
마치 Best Practices 백서의 요약본 같은…
자세한 수치는 등장하지 않습니다
그런 거 넣으면 혼납니다
슬라이드 공개 예정입니다
너무 열심히 적지 않으셔도 됩니다
5
단종되기도 했고…
6. 이 슬라이드에는 발표자의 개인 의견이 들어 있습니다
소속된 회사나 팀의 공식 의견과 다를 수 있습니다
6
같이 고생하면서 해결책을 고민하는
넥슨 IT본부 여러분 항상 감사합니다
7. 이것이 mongodb다 (희망편)
메모리에서 고속으로 처리되는 I/O
MMAP이니까…
인스턴스를 샤드에 추가하면 알아서 도는 Balancer
신속하게 끝나는 단위 moveChunk 작업
서비스가 살짝 멈칫거리다가 말 거야
게임 서비스는 밤에도 멈추지 않지만,
유저가 적으니 영향은 덜하겠지
7
9. 이것이 mongodb다 (절망편)
생각보다 잘 나오지 않는 단위 샤드의 성능 (Operations / sec)
끝나지 않는 moveChunk 작업
풀리지 않는 Cluster Lock
초기 mongodb 드라이버의 각종 버그는 심각했다…
Replica Set 지정해서 Failover 시험하면 잘 안 넘어가고…
떨어져 나가는 유저들
Timeout과 클라이언트 에러의 폭풍
‘베타’ 가 원래 그런 것 아닌가요 하하하…
9
10. 7년 같은 7일
왜 일어났나?
글쎄 왜 일어났을까.. 입사하기 전이라
사내 위키와 담당자들의 의견을 종합하였습니다
서비스 오픈 부하
(부족했지만) 샤딩을 안 한 것도 아니고…
mongoDB가 버텨줄 줄 알았다
Auto Sharding에 의존
그때만 해도 다들 mongo님이 다 해주실 줄 알았다고 한다
클러스터 전체에 잠금이…
Chunk migration 작업 시에 그렇다는 것은 나중에 알았다
10
11. 사용자 폭증
DB 데이터
& 부하 급증
밸런서 동작
청크 이전
DB Block
Timeout →
끊김
재접속 시도
악순환
11
13. FIFA Online 3 Shard Cluster
13
Shard (game)
Game
Server
Mongos
(game)
Mongos
(game)
Mongos
(player)
Mongos
(etc)
Mongos
(player)
Mongos
(etc)
mongod rs
sk:0, 16, 32, 48
mongod rs
sk:1, 17, 33, 49
….
Shard (player)
…. ….
config
DB
config
DB
config
DB
14. Mongos의 역할
Query Router
DB Query를 각 샤드로 분배하고 결과를 받는다
샤드 클러스터 관리 임무
Chunk Splitting
Balancing
흔히 간과하는 부분…
15. Mongos의 역할
Chunk Splitting
데이터를 일정한 크기의 논리 단위(chunk)로 쪼갠다
Config.chunks 컬렉션에 기록함
백그라운드 스캔 작업이 항상 돌고 있다
꺼버릴 수 있다
Balancing
쪼갠 청크를 고르게 분배
moveChunk
동작 시간을 지정할 수 있고, 꺼버릴 수 있다
16. preSplit
Balancing 때문에 망했으면, 사용하지 않으면 된다
미리 쪼개면 되지
Shard key를 지정하여 chunk를 미리 쪼갠다
청크는 mongos에서 관리하는 ‘논리적‘ 단위
키 어디서 어디까지는 어느 샤드에서 처리하라는 ‘매핑’
Mongos에 접속, config.chunks 컬렉션을 조회하여 확인
쪼갠 chunk를 특정 샤드로 지정한다
moveChunk 명령
17. preSplit
샤드를 쓰는 모든 컬렉션은 다음 과정을 거쳐서 만든다
sh.enableSharding (“somedb“)
sh.shardCollection (“somedb.coll”, { sk:1, _id:1 })
for … 1~64 …
sh.splitAt ( … )
sh.moveChunk ( … )
Shell로 리턴해도 바로 잠금이 풀리지 않아서 retry가 필요할 수 있음..
쿼리에 explain() 을 써서 실제로 처리하는 샤드를 확인 가능
18. Shard Key
분포도(Selectivity)가 좋은 키
만만한 것이 ObjectId
퍼블리셔 별 User Id
딱 찝어서 데이터를 가져올 수 있는 키 (Point query 가능)
…를 해싱해서 사용한다
연속적으로 들어오는 데이터라도 강제로 쪼갤 수 있다
예제
{ sk: 1, _id: 1 }
{ sk: 1, userid: 1 } sk: 해시값 (0..63)
19. ‘sk’ 필드 계산하기
쿼리를 날릴 때 sk 필드를 계산해서 붙여줘야 함
Mongoose 등을 사용한다면 ORM 로직에서 처리하게 할 수 있다
64개 정도면 적절하다고 예상했고, 실제로 적절했음
64 = 26, 데이터를 반씩 쪼개서 샤드를 2배 늘리기 좋음
왜 안썼을까?
20. ‘sk’ 필드 계산하기
Timestamp
‘초’ 단위의 정밀성
1초에도 수백건 이상의 요청이 들어올 수 있음
특히 insert가 빈번한 경우 문제가 된다
Counter
같은 시각에 들어왔더라도 counter 값은 다름
카운터 값을 64로 나눈 나머지를 쓴다
21. Hashed Sharding
간편하다
번거로운 presplit 과정이 필요가 없다
미리 나눠놓고 데이터를 입력하면 된다
_id로 쪼갰을 때도 잘 나뉜다
Point Query에 적합하다
SQL) SELECT … FROM Users WHERE UserId = ?
js) db.users.find({ userid: ObjectId(“xxxxxx”) })
db.adminCommand({ shardCollection: "db.col", key: { keycol: "hashed" }, numInitialChunks: 64 })
mongoDB 2.4~
22. Hashed Sharding
직접 관리하기 어렵다
청크를 직접 분할하고 옮기는 것은 가능
Sk 필드처럼 직관적인 범위가 없다
Sk 0~7은 1번, 8~15는 2번 샤드와 같은 배치가 불가능
mongos의 청크 분할과 balancer를 사용하는게 좋다
7년같은 7일을 당하지 않으려면 밸런서는 점검 시간에만 동작시킨다
23. Hashed Sharding
FO3에서는 아직 사용하지 않음
2.2로 서비스를 시작해서 앞에서 설명한 자체 샤딩을 구현했고,
이미 안정적으로 잘 굴러가고 있으므로 큰 필요성을 느끼지 못함
앞으로 적용할 곳이 있는지 보고 있음
간편하므로
로그 데이터라든가
25. 항상 주의하세요
샤드 키를 빼먹으면 쿼리가 전체 샤드로 갔다가 돌아온다
그러려고 쪼갠게 아닐텐데!
Map/reduce 보다는 aggregation framework
M/R은 Global Write Lock을 건다
2.6부터는 out 옵션도 추가됨 (write 시에 잠금이 생기겠지만)
집계 시 readPref를 설정해서 Secondary로 보내주는 것도 좋다
findAndModify 주의
_id로 찾는 게 아니면 쓰지 말자
어떤 종류의 쿼리가 어떻게 / 얼마나 들어올지 깊게 생각하고 나눠야 한다
27. Monitoring: MMS
해외 서비스에는 MongoDB Monitoring Service를 적용함
무료”였”다
꽤나 자세한 지표를 보여줬음
뭔가 조금씩 불편하긴 했지만 무료니까…
일부 국가에서 통신문제가 있음
베트남이 가끔…
중국이 꽤 자주 -_-…
아무래도 AWS라서
별도 계약 시 MMS Ops Manager를 사용할 수 있음
하지만 유료 서비스 쓰지 않을 것 다 압니다…
30. Monitoring: Tools
mongosniff
Profile 걸지 않고 쿼리 분석용 (wireShark도 사용 가능)
mongotop
어느 DB에 부하가 걸리고 있나 = db.adminCommand({top:1})
mongostat
대부분의 지표 = db.serverStatus()
mongod.log
Slow query 분석용 (default: 100ms)
31. Monitoring: metrics
Lock %
60 넘어가면 서버가 많이 힘들어하고 있는 것으로 판단
(잠금이 걸린 시간) / (모니터링 간격)
Page faults / sec
X0 ~ X00 넘어가기 시작하면 메모리가 부족한 것
단 점검 후 초반에 메모리가 예열(!)이 덜 되었을 땐 높을 수 있다
메모리에 데이터가 충분히 올라가지 않았다면 디스크에서 읽음
touch 명령, find() 등으로 full scan
32. Monitoring: metrics
Replication Lag
Secondary의 oplog time – Primary의 oplog time
몇 분 이상 밀리기 시작하면 복제에 문제가 있는 것
Replication Oplog Window
복제가 끊겼을 때 full sync 대신 얼마나 버틸 수 있는가
var c = db.getSisterDB("local").oplog.rs;
print(c.find().sort({$natural:-1}).limit(1)[0].ts.t
- c.find().sort({$natural:1}).limit(1)[0].ts.t, "sec")
← 이렇게 계산합니다
36. SSD 쓰세요
SSD 쓰세요, 두 번 쓰세요
36
NVMe (PCIe x4) 15k 2.5" 300G x 6
800G 900G
$2,150 $430
$4,300 $2,580
Software RAID Hardware RAID
200,000 900
20 µs 3.4 ms
14.6 PBW -
Dell.com 가격
RAID 1 / RAID 10
R70% / W30%
800G x 18,250
37. SSD 쓰세요
SSD 수명이 걱정된다고요?!
서비스 접을 때까지 써도 될 듯..
37
# fio-status -a
...
Reserve space status: Healthy; Reserves: 100.00%, warn at 10.00%
Active media: 100.00%
Rated PBW: 4.00 PB, 95.63% remaining
Lifetime data volumes:
Physical bytes written: 174,868,745,102,696
Physical bytes read : 142,721,083,007,568
RAM usage:
Current: 179,791,680 bytes
Peak : 179,999,680 bytes
...
38. Configurations: Storage
디스크 볼륨 구성
OS + Journal에 RAID 1로 하나
나머지는 RAID 10으로 몰빵
플래시 장비는 플래시 볼륨에 데이터를 모두 넣음
OS Readahead Configuration
사실 큰 차이를 보지 못했음
너무 낮추면 백업시 불리함
39. Configurations: Journal
RDBMS의 트랜잭션 로그 같은 것
더 설명이 必要韓紙?
성능 저하 있음
변경점을 로그에 미리 쓰고 나서 기록하는데 없으면 이상함
직접 구성한 서버에서는 반드시 사용함
mmap 엔진에서는 안쓰면 데이터를 깨먹을 위험이 있음
메모리 사용량이 두배로 나옴
Don’t Panic: 실제로 그만큼 쓰지는 않는다
40. Configurations: Oplog
복제 로그 (필수 요소)
세컨더리 잠깐 내렸다 올려도 oplog가 남아있다면 빠르게 따라잡음
…그러나 그만큼 메모리를 먹는다
Oplog를 계속 기록하므로
메모리에 항상 올라와 있다
41. Configurations: Oplog
얼마나 만들어지는지를 아는 것이 좋습니다
적당한 크기
최저 2-3시간, 최대 하루 정도까지
DB를 더 많이 괴롭히면(?) 더 많은 로그가 생성됨
메모리를 128GB 장착한 서버라면 10G쯤 써도 됨…
42. 했더니 도움이 된 것
Game DB와 Log DB 클러스터 분리
Game DB (Insert, Delete, Update, Select)
Log DB (Insert, Select)
로그 데이터가 메모리에 올라와 있을 필요가 없으니까
한 클러스터에 다른 부하를 섞지 말자
43. 했더니 도움이 된 것
선수 DB 변천사
Game DB에서 컬렉션을 떼어내 DB 분리
db 수준 잠금이니까
(부작용) DB 연결이 늘어남
게임 DB 클러스터에서 분리
게임 DB 장비를 반으로 줄이고 선수 DB 장비를 따로 구성함
떼어내야 산다 (2.6까지는…)
3.0의 mmap은 Collection Level Lock으로 개선
44. 했더니 도움이 된 것
Document 크기를 고정시킴
필요한 필드는 만들 때 채워둔다
업데이트는 in-place로 처리한다
db.serverStatus().metrics.operation.fastmod
usePowerOf2Sizes 옵션 (2.6 부터는 기본)
Update시 문서 이동을 줄여줌
임시 문서를 만들었다가 삭제하는 일이 잦다면 특히 유용하다
FO3 Transaction 구현에서 효과를 크게 봄
로그성 데이터에는 적합하지 않다 – 꺼야 함
(in-place 업데이트만 집계되는 건 아님)
45. 대규모 작업
데이터 이전 시에는 원격 서버에서!
작업자 PC에서 mongo 셸 띄우지 말 것
데이터가 원격 서버에서 작업자 컴퓨터 왔다가 감
서버끼리 직접 데이터를 주고받는 경우는 많지 않다
copydb, clone, cloneCollection 정도
46. 대규모 작업
셸은 싱글스레드
Thread 개체가 있지만 내부 테스트 용
보통 타 언어로 스크립트를 짜는게 더 빠르게 작업이 가능
병렬처리 꼭 하세요!
읽기는 각 샤드 mongod에서, 쓰기는 mongos로
단순 작업에는 dump / restore 또는 export / import 사용
느리다고 생각하면 3.0의 mongodb tools를 사용
47. mongos
중요한 컴포넌트이긴 한데…
샤딩의 핵심이기도 한데…
너무 적게 띄우지 말고
부하가 몰리면 메모리가 샌다
너무 많이 띄우지 말 것
100개 넘게 띄우지는 말라는 개발사의 충고
서버간 동기화는 공짜가 아니다 (config db 부하)
애플리케이션 서버와 연동해서 올리고 내리면 좋음
49. TokuMX
mongodb 2.4에서 파생된 엔진
MySQL TokuDB 엔진을 만든 그 Tokutek에서 만듦
장점도 많고…
높은 압축률 + 적당한 cpu 사용
높은 insert 성능, 낮은 I/O량
로그 저장에는 확실히 좋다
단점도 있고…
섞어서 못씀 → 클러스터를 따로 구축해야 함
불안함 (가끔 이유없이 사망)
우리 게임 DB로는 안 맞았음
52. mongoDB 3.0
원래는 2.8
어른의 사정으로 뻥튀기를 하지 않았을까
Storage Engine 도입
엔진간 데이터 포맷이 다르다!
DB나 컬렉션 단위로 섞어 쓸 수 없다
Replica set 안에서 섞을 수 있다
3rd party 엔진도 개발중
TokuMXse 아까 말한 TokuMX에서 엔진만 똑
RocksDB, In-Memory Engine, …
53. 엔진 섞어쓰기
티어를 둔 구성이 가능
쓸 일은 많지 않을 것 같지만…
백업에 특화된 엔진 등이 있다면?
점진적인 마이그레이션
rs3 엔진 변경, 재시작
복제 완료
rs2 엔진 변경, 재시작
복제 완료
rs1 엔진 변경, 재시작
…
mmap WT
Rocks
DB
rs1 (Primary) rs2 (Secondary)
rs3 (Secondary)
54. 성능 향상
Document Level Locking
journal 안써도 데이터가 깨지지 않음
안 쓰면 최대 60초까지 데이터를 잃을 수 있음
Replica set 구성으로 극복
NO IN-PLACE UPDATE
업데이트가 데이터를 바로 교체하지 않는다
먼저 쓰고, 구 버전은 나중에 지워짐
문서 크기를 가급적 키우지 않는 것이 좋을 듯
wiredTiger
64. 300317 274006 297663
40300319 40274008 40297665
63065603 57540636 62508349
300319 274008 297665
18360 10559 10900
file storage+idx
Number of Rows
64
wt에 저널을 끄면 좀 나아지기는 하지만..
서비스용 장비에서 테스트를 다시 해볼 예정
65. mongoDB 3.0: 그 밖의 변경점
MMAPv1 엔진
collection level lock으로 개선됨
explain 변경
이제 쿼리를 실제로 실행하지 않고 질의 계획을 볼 수 있다
mongoimport / export / dump / restore
Go로 재작성: 이제 --dbpath 사용 못함
Batch 처리 및 멀티스레드 작업 지원
Client Driver 업데이트 필요
구버전 드라이버 접속 시 호환성 문제가 발생함: 인증, 시스템 컬렉션..
66. 올해의 목표와 연구과제
mongoDB upgrade
2.4 → 3.0
영향이 적은 쪽부터 부분적으로
microsharding
한 서버에 여러 다른 샤드의 인스턴스를 띄움
샤드 수가 늘어나면 클러스터 전체 성능이 늘어나는 효과
3.0 WT 엔진은 사용하는 캐시 메모리 크기를 정할 수 있게 됨
MMAP은 불가능하여 cgroups 등을 사용해야 했음
68. 참고
Hash based sharding
http://www.slideshare.net/mongodb/hash-based-sharding
Introduction to wiredTiger
http://www.slideshare.net/vkarpov15/mongodb-miami-meetup-12615-introduction-to-wiredtiger
Acme Benchmarking
http://www.acmebenchmarking.com/
MongoDB 완벽 가이드 2판 (한국어판)
http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-095-9
mongoDB Operations Best Practices
http://s3.amazonaws.com/info-mongodb-com/10gen-MongoDB_Operations_Best_Practices.pdf
mongoDB Performance Best Practices
http://s3.amazonaws.com/info-mongodb-com/MongoDB-Performance-Best-Practices.pdf
Shaping the Future of Travel with MongoDB
http://www.slideshare.net/mongodb/shaping-the-future-of-travel-with-mongodb/21
69. Q & A
자동 sharding을 믿지 말자
해시할 키를 잘 잡아서 미리 쪼개놓자
모니터링을 잘 하자
CPU 전원 설정은 의외의 튜닝 포인트
데이터 종류 별로 클러스터를 분리하자
새 버전이 나왔으니 잘 살펴보고 업그레이드를 해보자
70. Q & A (추가)
타 DB에 비해서 MongoDB를 쓰게 된 이유는? 추천할 만한 이유가 있다면?
서비스를 개발하고 오픈하던 시기에는 비정형 데이터를 넣을 쓸만한 DBMS가
없었던 것이 사실이나, 지금은 그렇지 않습니다.
Ex) PostgreSQL, MySQL DocStore, SQL Server 차기 버전 등…
굳이 처음부터 MongoDB를 고려하기 보다 익숙한 RDBMS로 빠르게 개발할 수
있다면 그것도 한 방법입니다.
단 샤딩만큼은 기존 RDBMS에 비해 MongoDB가 제공하는 강력한 장점입니다.
70
저는 MongoDB 쓰지 마세요 라고 하지 않았습니다!
71. Q & A (추가)
아까 SSD 쓰라고 할 때 Software RAID를 쓰라고 했는데 왜죠?
SAS / SATA SSD를 쓰면 RAID 컨트롤러를 사용할 수 있지만
카드형은 그게 안되니까요. 속도는 이미 빠르니 내결함성을 보장하면 되죠.
C***hbase 써봤나요?
안 써봤어요.
71