568. 몽고DB 샤딩 청크 마이그레이션 백그라운드 밸런싱 모형
⚠️ 이 문서는 데이터베이스 용량이 단일 서버의 디스크를 초과할 때 데이터를 여러 대의 서버(Shard)로 쪼개어 분산 저장하는 기술인 '샤딩(Sharding)' 환경에서, 특정 샤드 서버에만 데이터가 몰려 터지는 현상을 막기 위해 MongoDB가 쪼개진 데이터 조각(Chunk)들을 백그라운드에서 자동으로 이사(Migration)시키고 공평하게 맞춰주는 '오토 밸런싱(Auto-balancing)' 기술을 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 샤딩은 데이터를 샤드 키(Shard Key) 기준으로 자르는 기술이다. 잘라진 덩어리를 '청크(Chunk)'라고 부르며, 몽고DB는 이 청크들의 개수를 세어 각 샤드 서버에 골고루 분배하는 중앙 통제 프로세스(Balancer)를 백그라운드에 상주시킨다.
- 가치: 운영자가 수동으로 데이터를 옮길 필요 없이, 서버 3대 중 1대가 디스크가 꽉 찰 조짐이 보이면 몽고DB 스스로 덜 바쁜 새벽 시간에 청크를 옆 서버로 이사시켜 용량과 트래픽 부하를 자동으로 분산(Load Balancing)해 준다.
- 기술 체계: 샤드 키의 선택(해시 vs 범위)에 따라 핫스팟(Hotspot) 쏠림 현상이 좌우되며, 청크 사이즈(기본 64MB)를 쪼개는 스플릿(Split) 작업과 청크를 통째로 옮기는 마이그레이션(Migration) 작업이 네트워크 IO를 유발하므로 정교한 스케줄링 튜닝이 필수다.
Ⅰ. 샤딩의 함정: 핫스팟(Hotspot)과 청크의 탄생
데이터를 쪼갰다고 무조건 공평해지는 것은 아니다.
- 샤드 키 (Shard Key)의 딜레마:
- 유저 데이터를 3대의 서버(샤드 A, B, C)로 나눌 때 기준이 필요하다.
- '가입일'을 샤드 키로 쓴다면? 옛날 가입자는 A에, 어제 가입자는 B에, 오늘 가입자는 C에 들어간다. 문제는 사람들이 오늘 가입자 정보만 미친 듯이 조회하기 때문에 C 서버만 CPU가 100%를 치고 A, B는 놀게 된다. 이를 핫스팟(Hotspot) 쏠림 현상이라 부른다.
- 청크 (Chunk)의 분할 (Split):
- 몽고DB는 데이터를 무식하게 1건 단위로 관리하지 않는다.
가입일: 1월 1일 ~ 1월 31일처럼 묶음을 만들어 이를 **'청크'**라고 부른다 (보통 64MB 사이즈). - 데이터가 쌓여 1월 청크가 64MB를 넘어서면, 몽고DB는 즉시 1~15일, 16~31일 2개의 청크로 반갈죽(Split) 해버린다.
- 몽고DB는 데이터를 무식하게 1건 단위로 관리하지 않는다.
📢 섹션 요약 비유: 도서관 책을 3개의 창고에 나눌 때, '출판 연도'로 나누면 2023년 책이 있는 3번 창고에만 사람들이 미어터져(핫스팟) 무너집니다. 책을 그냥 64권 단위(청크)로 묶어서 박스에 담고, 박스가 꽉 차면 박스를 두 개로 쪼개는(Split) 방식이 몽고DB의 데이터 포장법입니다.
Ⅱ. 백그라운드 밸런서 (Balancer)의 마이그레이션
어느 한쪽 창고가 꽉 차면 짐을 자동으로 옆 창고로 밀어낸다.
- 밸런싱 조건의 트리거:
mongos(라우터) 내부에 숨어있는 밸런서 프로세스는 항상 3대 샤드 서버의 '청크 개수'를 세고 있다.- 샤드 A가 청크를 100개 가졌는데, 샤드 C가 청크를 110개 가졌다면? 차이가 10개 나므로 밸런서가 깨어나서 "C에서 A로 청크를 좀 옮겨야겠다!"라고 판단한다.
- 라이브 마이그레이션 (Live Migration):
- C 서버의 특정 청크(64MB) 데이터를 A 서버로 네트워크를 통해 전송(복사)하기 시작한다.
- 이때 유저가 해당 데이터를 수정(Update)하면? 몽고DB는 수정된 내역을 임시 장부(Oplog/Change log)에 적어뒀다가, 복사가 끝난 직후 재빨리 새 서버(A)에 반영해 준다. 무중단 이사가 가능하다.
- 메타데이터 (Config Server) 업데이트:
- 복사가 100% 안전하게 끝나면, 중앙의 Config 서버는 "자, 오늘부터 1월 데이터 청크는 C가 아니라 A 창고에 있습니다"라고 간판(메타데이터)을 바꿔 달고, 기존 C 서버의 원본 데이터를 쿨하게 지워버린다.
📢 섹션 요약 비유: 3번 창고에 박스가 10개나 더 많아지면, 새벽에 청소부(밸런서)가 조용히 박스(청크) 하나를 수레에 싣고 1번 창고로 옮깁니다. 옮기는 와중에 손님이 박스 안의 책에 낙서를 하면(Update), 청소부가 포스트잇에 적어뒀다가 1번 창고에 도착하자마자 똑같이 낙서를 반영해 줍니다(라이브 마이그레이션). 이사가 끝나면 중앙 안내데스크(Config 서버)의 지도만 싹 바꿔줍니다.
Ⅲ. 오버헤드 통제: 밸런싱 윈도우 (Balancing Window)
청소부가 너무 부지런하면 손님들이 밥을 못 먹는다.
- 마이그레이션 폭풍 (Migration Storm):
- 64MB짜리 청크를 네트워크로 옮기는 작업은 서버의 디스크 I/O와 대역폭을 어마어마하게 갉아먹는다.
- 낮 12시에 쇼핑몰 트래픽이 터져 서버가 헉헉대고 있는데, 하필 그때 밸런서가 깨어나 청크를 100개씩 이사시키기 시작하면 DB가 완전히 뻗어버리는 대참사가 난다.
- 밸런싱 스케줄 제어 (Window 설정):
- 똑똑한 운영자(DBA)는 몽고DB 설정에서 **"밸런싱 작업은 손님이 없는 새벽 2시부터 5시까지만 수행해라(Balancing Window)"**라고 강제 스케줄을 걸어둔다.
- 샤드 키(해시)의 근본적 해결:
- 애초에 이사를 자주 안 하게 하려면 처음부터 데이터를 잘 흩뿌려야 한다.
- 최근에는 '가입일' 같은 순차적인 범위(Range) 키 대신, 고객 ID를 수학적으로 다져버리는 해시(Hashed) 샤드 키를 써서 데이터가 들어올 때부터 A, B, C 서버에 1:1:1로 완벽히 쪼개지게 만들어 밸런서가 할 일 자체를 없애는 아키텍처가 대세다.
📢 섹션 요약 비유: 점심시간에 식당이 미어터지는데 알바생이 테이블 간격 맞춘다며 무거운 식탁(청크)을 질질 끌고 다니면 손님들이 화를 냅니다(오버헤드 폭발). 식탁 배치는 반드시 손님이 다 나간 새벽(Window)에만 하도록 지시해야 하며, 가장 좋은 건 처음부터 손님들을 각 테이블에 번호표 뽑기로 기가 막히게 분산(해시 샤딩)시켜 식탁을 옮길 일 자체를 안 만드는 것입니다.