DB/마스터링 몽고DB 7.0

[2장] 몽고DB 아키텍처

꾸준함. 2025. 7. 5. 01:04

서론

  • 복제 기술은 몽고DB의 분산 아키텍처를 구성하는 근간이 되는 요소이며 동일한 데이터를 여러 서버에 분산하여 저장함으로써 시스템의 접근성을 크게 향상함
    • 예기치 않은 장애 상황에서도 중단 없는 안정적인 서비스를 제공할 수 있게 하여, 시스템의 신뢰성과 가용성을 보장

 

  • 샤딩은 데이터를 여러 서버에 효율적으로 분산하는 수평적 확장 전략
    • 서비스의 규모가 확대되고 처리해야 할 데이터의 양이 급증하는 상황에서, 샤딩 기술은 다수의 서버를 활용하여 읽기와 쓰기 작업을 원활하게 처리할 수 있게 함
    • 시스템의 처리 능력을 효과적으로 확장하고 대규모 데이터 환경에서도 최적의 성능을 유지할 수 있는 비결

 

복제와 샤딩

  • 복제는 데이터를 여러 위치에 중복으로 저장하여 시스템의 안정성과 데이터 접근성을 높이는 기술
  • 샤딩은 대규모 데이터베이스를 작은 단위인 샤드로 나누어 각각을 별도의 서버에서 관리하는 방식
    • 각 샤드도 데이터의 안전한 보관과 서비스 연속성을 위해 복제 시스템을 함께 운영해야 함
    • 만약 특정 샤드가 단일 서버로만 운영될 경우, 해당 서버 장애 시 데이터에 접근할 수 없음
    • 하지만 각 샤드에 복제 시스템을 구축할 경우 서버 장애 상황에서도 중단 없는 서비스가 가능해짐

 

복제

  • 몽고DB의 복제본 세트는 동일한 데이터를 공유하는 여러 mongod 프로세스의 그룹이며 이는 데이터의 중복 저장과 고가용성을 보장하여 실제 서비스 환경의 근간이 됨
  • 몽고DB 복제본 세트에서 주 서버는 모든 쓰기 작업을 담당하며, 데이터의 변경 사항을 oplog에 기록
    • 복제본 세트 내에서는 단 하나의 주 서버만이 존재할 수 있음

 

  • 보조 서버들은 주 서버의 oplog를 참조하여 동일한 작업을 수행함으로써 데이터의 일관성을 유지함
    • 주 서버에 장애가 발생할 경우 자격을 갖춘 보조 서버 중 하나가 새로운 주 서버로 선출되는 과정을 거쳐 주 서버로 승격함

 

  • 읽기 작업이 많은 서비스에는 이러한 분산 저장 방식을 통해 여러 서버에 부하를 분산시켜 데이터 검색 속도를 향상할 수 있음

 

https://www.mongodb.com/ko-kr/docs/manual/core/replica-set-architecture-three-members/

 

 

1. 복제본 세트 선출

  • 몽고DB는 분산 시스템의 데이터 일관성 보장을 위해 RAFT 합의 알고리즘을 기반으로 한 프로토콜을 사용하는데 해당 프로토콜은 복제본 세트에서 주 노드를 선출하는 투표 메커니즘을 포함하고 있음
  • 주 서버를 선출하는 투표 메커니즘은 다음과 같은 상황에서 시작될 수 있음
    • 복제본 세트의 서버 추가 또는 제거
    • 복제본 세트 초기화
    • 주 서버와 보조 서버 간 Heartbeat 응답 지연 시간이 허용 범위를 초과하는 경우

 

  • 몽고DB 드라이버는 주 서버 장애를 감지하고 특정 읽기나 쓰기 작업을 자동으로 재시도할 수 있어, 선거 과정에서 추가적인 안정성을 제공함
  • 주 서버가 사용 불가능한 상태가 되면, 보조 서버들은 새로운 주 서버 선출을 위한 투표를 진행
    • 가장 최근의 쓰기 기록을 보유한 서버가 선거에서 당선될 가능성이 높으며, 이는 이전 주 서버가 세트에 재참여할 때 발생할 수 있는 데이터 롤백 가능성을 최소화시킴
    • 선거가 완료된 후에는 일정 기간 새로운 선거를 시작할 수 없는 동결 기간이 적용되는데 이는 시스템의 불안정성을 초래할 수 있는 연속적인 선거를 방지하려는 조치

 

  • 복제본 세트는 새로운 주 서버가 선출될 때까지 쓰기 작업을 수행할 수 없지만 보조 서버에서의 읽기 작업이 설정된 경우, 읽기 작업은 계속 처리가 가능함

 

https://www.mongodb.com/docs/manual/core/replica-set-elections/

 

1.1 구성원 우선순위

  • 안정적인 주 서버가 구성되면, 선출 알고리즘은 가장 높은 우선순위를 가진 보조 서버가 선거를 시작할 수 있도록 함
  • 구성원의 우선순위는 선거의 시작 시점과 결과에 모두 영향을 미치며 높은 우선순위를 가진 보조 서버가 더 빠르게 선거를 시작하고 당선될 가능성이 높음
    • 그러나 더 높은 우선순위를 가진 구성원이 있더라도 낮은 우선순위의 구성원이 일시적으로 주 서버 임무를 수행할 수 있으며 가장 높은 우선순위를 가진 구성원이 주 서버가 될 때까지 선거 과정이 계속됨

 

  • 복제본 세트는 최대 50개의 구성원을 포함할 수 있지만 투표권을 가진 구성원은 최대 7개로 제한되어 있음
    • 투표권이 없는 구성원의 우선순위는 반드시 0으로 설정되어야 함
    • 우선순위가 0인 구성원은 주 서버가 될 수 없으며 선거를 요청할 수도 없음

 

2. 복제본 세트 oplog

  • oplog는 몽고DB 데이터베이스의 모든 데이터 변경 작업을 차례대로 기록하는 특수한 제한 컬렉션
  • 몽고DB에서 모든 쓰기 작업은 우선 주 서버에서 실행된 후 해당 서버의 oplog에 기록됨
    • 이후 보조 서버들이 해당 작업을 비동기적으로 복제하여 적용됨
    • 복제본 세트의 모든 구성원은 local.oplog.rs 컬렉션에 oplog의 사본을 보관하여 데이터베이스의 최신 상태를 유지함

 

  • 복제 기능을 지원하기 위해 복제본 세트의 모든 구성원은 서로 하트비트 혹은 ping을 주고받으며 각 보조 구성원은 다른 구성원으로부터 oplog 항목을 가져올 수 있음
  • oplog의 모든 작업은 멱등성을 가지고 있어, 동일한 작업을 N번 실행해도 항상 같은 결과를 보장함

 

2.1 oplog 윈도

  • oplog 항목에는 타임스탬프가 포함되어 있으며, oplog 윈도는 로그에 기록된 가장 최근 타임스탬프와 가장 오래된 타임스탬프 사이의 시간 간격을 의미함
  • 보조 서버가 주 서버와의 연결이 끊어진 경우, 해당 oplog 윈도 기간 내에 재연결이 이루어져야만 복제를 통한 재동기화가 가능함
  • 시스템은 다음과 같은 조건에서만 oplog 항목을 삭제함
    • oplog가 설정된 최대 용량에 도달했고, oplog 항목이 호스트 시스템 시간을 기준으로 지정된 보존 기간을 초과함
    • 최소 oplog 보존 기간이 설정되지 않은 경우, 몽고DB는 기본 설정에 따라 oplog가 최대 크기를 초과하지 않도록 가장 오래된 항목부터 차례대로 제거함

 

3. 복제본 세트 배포 아키텍처

  • 일반적인 운영 환경에서는 3개의 구성원으로 이루어진 복제본 세트를 배포하는 것이 표준이며 이러한 구성은 데이터 중복성과 장애 복구 능력을 제공함
  • 효율적인 복제본 세트 구성을 위해 다음 사항들을 고려해야 함
    • 네트워크 분할 상황에서 의사결정이 분산되는 것을 방지하고, 더 큰 네트워크 세그먼트에서 쓰기 작업이 가능하도록 홀수 개의 투표 구성원을 유지 (PSS 구조)
    • 투표 구성원이 짝수인 경우, 데이터를 보유한 새로운 투표 구성원을 추가하는 것이 바람직하지만, 어려운 경우에는 중재자인 Arbiter를 도입할 수 있음 (PSA 구조)
    • 백업이나 보고 등 특수 목적을 위해 숨김 구성원이나 지연 구성원을 추가할 수 있음
    • 데이터 센터 장애에 대비하여 최소한 하나의 구성원은 별도의 데이터 센터에 배치해야 함

 

3.1 복제본 세트 중재자 (Arbiter)

  • 주 서버와 보조 서버는 있으나 예산상의 제약으로 추가 보조 서버를 구축할 수 없는 경우, 복제본 세트에 중재자를 포함할 수 있음
  • 중재자는 주 서버 선출 과정에는 참여하지만, 실제 데이터의 복사본은 보유하지 않으며 주 서버 임무를 수행할 수도 없음
    • 중재자는 선거 과정에서 한 표의 투표권만을 행사할 수 있으며, 기본적으로 우선순위는 0으로 설정됨

 

3.2 숨김 복제본 세트 구성원

  • 숨김 구성원은 주 서버 임무를 수행할 수 없으며, 클라이언트 애플리케이션에서도 확인할 수 없음
  • 그러나 이러한 비가시성에도 불구하고, 숨김 구성원은 선거 과정에 참여하고 투표할 수 있는 권한을 유지함
  • 숨김 서버는 주로 백업 작업을 수행하거나 특정 보고서 쿼리를 실행하기 위한 전용 복제본 세트 구성원으로 활용됨
  • 숨김 서버를 설정하고 해당 구성원이 주 서버로 선출되는 것을 방지하기 위해서는, 우선순위를 0으로 설정하고 hidden 매개변수를 true로 지정하면 됨

 

 

 

 

3.3 지연 복제 세트 구성원

  • 지연 구성원은 숨김 구성원의 특수한 형태로, 원본 oplog로부터 작업을 복제하고 적용할 때 의도적인 시간 지연을 두어 복제본 세트의 과거 상태를 유지함
    • i.g. 현재 시각이 12:07이고 구성원의 지연 시간이 1시간으로 설정되어 있다면, 해당 지연 구성원은 11:07 이전까지의 작업만을 반영한 상태를 유지하게 됨

 

  • 지연 구성원은 데이터베이스의 지속적인 백업과 실시간 변경 기록을 담당하며, 휴먼 에러에 대비한 안전장치 임무를 수행함

 

 

 

 

4. 쓰기 보장 수준 (Write Concern)

  • 쓰기 보장 수준은 몽고DB가 복제본 세트에서 쓰기 작업의 완료를 확인하는 방식을 결정하며 이는 데이터가 지정된 개수의 서버에 성공적으로 기록되었는지 확인한 후에만 쓰기 작업을 승인하는 방식으로 작동함

 

4.1 쓰기 보장 수준의 구성 요소

쓰기 보장 수준에는 다음과 같은 필드가 포함될 수 있습니다.

  • w 매개변수는 쓰기 작업의 확인이 필요한 복제본 세트 구성원의 수를 지정하며 쓰기 보장 수준은 다음과 같은 <value>들로 설정할 수 있음
    • 0: 확인 절차 없이 쓰기 작업이 진행되며 가장 낮은 데이터 안정성을 가지지만, 최고의 성능을 제공함
    • 1: 주 서버로부터만 확인을 받음
    • 숫자: 지정한 수만큼의 복제본 세트 구성원으로부터 확인을 받음
    • "majority": 복제본 세트 구성원의 과반수로부터 확인을 받으며 몽고DB 5.0 버전부터 default 값

 

  • j: 쓰기 작업이 디스크의 저널에 기록되었는지 확인하며 true로 설정할 경우 저널 기록이 완료될 때까지 대기함
  • wtimeout: 쓰기 보장 수준에 관한 시간제한을 밀리초 단위로 설정하며 지정된 시간 내에 필요한 수준의 확인이 이루어지지 않으면 오류가 발생함
    • 쓰기 작업의 실패나 롤백을 의미하는 것은 아니며
    • 단순히 지정된 시간을 초과하여 쓰기가 차단되는 것을 방지하는 역할

 

{ w: <value>, j: <boolean>, wtimeout: <number> }

 

  • 몽고DB 4.4 버전부터는 복제본 세트와 샤딩 클러스터 모두에서 전역 기본 쓰기 보장 수준을 설정할 수 있음
    • 개별적으로 쓰기 보장 수준이 지정되지 않은 모든 작업은 해당 전역 기본값을 따르게 됨
    • setDefaultRWConcern 명령어를 사용하면 읽기 또는 쓰기 보장 수준에 관한 전역 기본값을 설정할 수 있음

 

 

 

  • 몽고DB 5.0 버전부터는 기본 쓰기 보장 수준이 { w: "majority" }로 설정되어 있지만 중재자가 포함된 배포에서는 다음과 같은 예외 상황이 적용됨
    • 투표 과반수는 투표할 수 있는 구성원 수의 절반에 1을 더한 후 내림한 값으로 계산됨; 데이터를 보유한 투표 가능 구성원의 수가 해당 투표 과반수에 미치지 못한 경우, 기본 쓰기 보장 수준은 { w: 1 }으로 조정됨
    • 그 외의 모든 경우에는 기본 쓰기 보장 수준이 { w: "majority" }를 유지

 

4.2 쓰기 보장 수준의 중요성

  • 쓰기 보장 수준의 선택은 시스템의 성능과 데이터의 내구성 모두에 영향을 미침
    • 성능 측면: w: 0과 같은 낮은 쓰기 보장 수준은 쓰기 작업의 지연 시간을 줄여 성능을 향상할 수 있지만 데이터의 안정성을 저해할 수 있는 위험 존재
    • 내구성 측면: w: "majority"와 같은 높은 쓰기 보장 수준은 과반수 서버로부터의 확인을 통해 데이터의 안전성을 보장하지만 쓰기 작업에 약간의 지연이 발생할 수 있음

 

5. 읽기 선호도 (Read Concern)

  • 읽기 선호도는 클라이언트가 복제본 세트의 서버들에게 읽기 작업을 분배하는 방식을 결정함
  • 기본적으로 모든 읽기 작업은 주 서버로 전달되지만, 읽기 선호도를 조정하여 보조 서버들에게 읽기 부하를 분산시킬 수 있음

 

5.1 읽기 선호도 구성 요소

  • 몽고DB는 다음과 같은 다섯 가지 읽기 선호도 모드를 제공
    • primary: 모든 읽기 작업을 주 서버로 전달 (default)
    • primaryPreferred: 먼저 주 서버에서 읽기를 수행하며, 불가능한 경우 보조 서버를 사용
    • secondary: 모든 읽기 작업을 보조 서버로 전달
    • secondaryPreferred: 먼저 보조 서버에서 읽기를 수행하며, 불가능한 경우 주 서버를 사용
    • nearest: 서버의 상태와 관계없이 네트워크 지연이 가장 낮은 서버에서 읽기를 수행

 

  • 이러한 읽기 선호도 모드 외에도 다음과 같은 추가 옵션을 설정할 수 있음
    • 태그 세트: 복제본 세트 서버에 사용자 정의 태그를 지정하여 읽기 선호도를 세밀하게 조정할 수 있으며 이를 통해 클라이언트는 특정 태그가 지정된 서버로 읽기 작업을 전달할 수 있음
    • 최대 지연 시간: 주 서버에서 보조 서버로의 복제 지연을 의미하며 해당 설정을 통해 보조 서버의 데이터가 얼마나 오래되었을 때 해당 서버를 읽기 작업에서 제외할지 지정할 수 있음

 

5.2 읽기 선호도의 중요성

  • 읽기 선호도의 선택은 시스템의 성능과 가용성에 다음과 같은 영향을 미침
    • 성능 측면: 읽기 작업을 보조 서버로 분산시킴으로써 주 서버의 부하를 줄일 수 있어 전체적인 시스템 성능이 향상됨
    • 가용성 측면: 주 서버에 장애가 발생하더라도, 읽기 선호도 모드 설정에 따라 보조 서버를 통해 지속적인 읽기 작업이 가능해짐

 

6. 읽기 보장 수준

  • 읽기 보장 수준은 복제본 세트와 샤딩된 클러스터에서 읽어 들인 데이터의 일관성과 격리 특성을 결정
    • 해당 수준을 조정함으로써 읽기 작업에서의 데이터 가시성을 제어할 수 있으며, 이를 통해 원하는 수준의 데이터 일관성과 격리르 확보 가능

 

6.1 읽기 보장 수준의 구성 요소

  • 몽고DB에서 지원하는 읽기 보장 수준은 다음과 같음
    • "local": 복제 상태와 관계없이 쿼리 시작 시점에 몽고DB 인스턴스에서 접근할 수 있는 최신 데이터를 반환 (default)
    • "available": 쿼리 시점에 분산 시스템에서 즉시 사용 가능한 데이터를 반환하며 이는 가장 빠른 응답 시간을 제공하지만, 데이터의 일관성은 보장하지 않음
    • "majority": 복제본 세트 구성원의 과반수가 확인한 데이터를 반환하여 높은 수준의 데이터 일관성을 보장
    • "linearizable": 읽기 작업 시작 이전에 완료된 모든 과반수 확인 쓰기를 반영하는 데이터를 반환함으로써 최고 수준의 데이터 일관성을 제공
    • "snapshot": 모든 복제본 세트 구성원에서 특정 시점의 데이터를 반환

 

6.2 읽기 보장 수준의 중요성

  • 읽기 보장 수준의 선택은 데이터의 일관성과 격리성에 다음과 같은 영향을 미침
    • 일관성 측면: "majority"나 "linearizable"과 같은 높은 수준의 읽기 보장을 설정하면 복제본 세트의 모든 서버에서 일관된 데이터가 반환되도록 보장할 수 있음
    • 격리성 측면: "snapshot" 읽기 보장 수준을 사용하면 트랜잭션 전체에서 일관된 데이터 뷰를 유지할 수 있으며, 동시에 발생하는 쓰기 작업으로부터 트랜잭션을 격리할 수 있음

 

7. 복제 메서드

  • mongosh는 복제본 세트를 쉽게 관리할 수 있는 다양한 셸 도우미 메서드를 제공하며 다음은 복제된 몽고DB 환경을 관리하는 데 필요한 주요 메서드들
    • rs.add(): 복제본 세트에 새로운 구성원 추가
    • rs.addArb(): 복제본 세트에 중재자 추가
    • rs.conf(): 복제본 세트의 현재 구성 정보 표시
    • rs.initiate(): 새로운 복제본 세트를 초기화
    • rs.printReplicationInfo(): 주 서버 관점에서의 복제본 세트 상태 요약 제공
    • rs.status(): 복제본 세트의 현재 상태 정보를 제공
    • rs.reconfig(): 기존 복제본 세트의 구성을 새로운 설정으로 변경
    • rs.stepDown(): 현재 주 서버를 보조 서버로 강제 전환하여 새로운 선거를 시작

 

  • 앞서 열거한 기본적인 복제 메서드 외에도 특수한 작업을 위한 복제 명령어들이 있음
    • i.g. "replSetResizeOplog" 명령은 복제본 세트의 가변 oplog 크기를 조정할 수 있음

 

샤딩

  • 몽고DB는 샤딩을 통해 수평적 확장을 지원함
  • 샤딩은 데이터를 여러 프로세스에 분산시키는 방식으로, 대규모 데이터의 관리와 구성에 핵심적인 역할을 수행
    • 각 샤드는 독립된 데이터베이스 서버 인스턴스에 저장되어 시스템의 부하를 분산시키고 효율적인 데이터 관리를 가능하게 함

 

1. 왜 샤딩이 필요한가?

  • 데이터베이스가 급격히 성장하여 최대 용량에 근접하면 데이터 조회가 느려지는 성능 저하를 유발할 수 있음
  • 또한 대부분의 시스템은 효율적으로 관리할 수 있는 데이터양에 제한이 있어, 이를 초과할 경우 시스템 장애가 발생할 수 있음
  • 이러한 시스템 성장 관리를 위해 다음과 같은 두 가지 주요 전략이 있음
    • 수직 확장: 단일 서버의 성능을 향상하는 방식으로, CPU 업그레이드, RAM 증설, 저장 공간 확장 등이 포함되지만 단일 서버가 처리할 수 있는 작업량에는 기술적 한계가 존재하여 해당 방식은 근본적인 제약이 존재
    • 수평 확장: 시스템의 데이터와 작업량을 여러 서버에 분산시키는 방식으로, 필요에 따라 서버 수를 증가시키는 방식으로 각 서버가 전체 작업의 일부만 처리하므로 단일 고성능 서버보다 효율적일 수 있음

 

2. 샤딩 클러스터의 주요 요소

몽고DB의 샤딩 클러스터는 크게 세 가지 핵심 요소로 구성됩니다.

  • 샤드: 클러스터 내에서 데이터를 분산 저장하는 복제본 집합; 클러스터는 필요에 따라 여러 개의 샤드를 보유할 수 있으며, 각 샤드는 전체 데이터 중 자신만의 고유한 부분을 저장함
  • mongos: 클라이언트 애플리케이션의 쿼리를 처리하는 라우터 업무를 수행; 읽기와 쓰기 작업을 효율적으로 관리하며 클라이언트의 요청을 적절한 샤드로 전달하고 여러 샤드에서 받은 결과를 하나의 응답으로 통합하는 역할 수행
  • 구성 서버: 복제 세트 형태로 운영되며 샤딩 관련 메타데이터를 저장하는 특수 데이터베이스; 해당 메타데이터에는 샤딩된 데이터의 현재 상태와 구조, 샤딩된 컬렉션 목록, 그리고 라우팅 정보와 같은 중요한 정보가 포함되어 있음

 

https://www.oreilly.com/library/view/mastering-mongodb-3x/9781783982608/d9f7fa19-f9a1-4a1e-864b-e487d1c6e78a.xhtml

 

  • 몽고DB의 데이터 샤딩은 컬렉션 단위로 이루어지며 하나의 컬렉션에 속한 데이터가 클러스터 내 여러 샤드에 분산되어 저장되는 방식
    • 각 데이터베이스는 자신만의 주 샤드를 가지고 있는데, 이는 해당 데이터베이스에서 샤딩되지 않은 모든 컬렉션을 저장하는 역할을 수행

 

  • 새로운 데이터베이스가 생성될 때, mongos 프로세스는 클러스터 내에서 가장 적은 데이터를 보유한 샤드를 주 샤드로 자동 선택하며 이때 listDatabases 명령어가 반환하는 totalSize 필드가 선택 기준의 하나로 활용됨
  • 데이터베이스가 생성된 후에도 movePrimary 명령어를 사용하여 주 샤드를 다른 샤드로 이동할 수 있음

 

3. 마이크로 샤딩

  • 일반적인 샤딩 방식이 하나의 서버에 하나의 샤드를 할당하는 것과 달리, 마이크로 샤딩은 단일 서버에 여러 개의 샤드를 배치하는 방식
  • 마이크로 샤딩은 각 샤드가 저장하는 데이터의 크기가 비교적 작을 때 특히 유용한 전략
    • 단일 서버에 다수의 샤드를 통합함으로써 서버 자원을 보다 효율적으로 활용할 수 있으며, 이는 결과적으로 하드우어 활용도를 높이는 효과를 가져옴

 

  • 마이크로 샤딩 방식을 도입할 때는 신중한 자원 관리가 매우 중요함
    • 같은 서버에서 여러 몽고DB 프로세스가 동시에 실행될 때 발생할 수 있는 자원 충돌을 방지하기 위해서는 각 프로세스에 적절한 양의 자원을 할당해야 함
    • 특히 각 몽고DB 프로세스의 캐시 크기 설정이 중요한데, 이는 WiredTiger 스토리지 엔진의 storage.wiredTiger.engineConfig.cacheSizeGB 설정을 통해 조정할 수 있으며 해당 캐시는 각 프로세스의 작업 세트를 충분히 수용할 수 있을 만큼의 크기를 확보해야 함 (default 값은 전체 RAM에서 1GB를 뺀 값의 50%)
    • 단일 서버에서 여러 몽고DB 프로세스를 운영할 때는 해당 설정값을 조정해야 하며 모든 프로세스가 사용하는 총 메모리가 서버의 가용 RAM을 초과하지 않도록 주의해야 함
    • ex) 16GB RAM이 탑재된 서버에서 두 개의 몽고DB 프로세스를 실행하는 경우 각 프로세스의 storage.wiredTiger.engineConfig.cacheSizeGB 값을 기본값인 50%가 아닌 25%인 4GB로 설정하는 것이 바람직함

 

4. 샤딩의 이점

샤딩은 다음과 같은 세 가지 주요 이점을 제공합니다.

  • 읽기와 쓰기 성능 향상: 여러 샤드에 데이터를 분산 저장하면 병렬처리할 수 있으며, 샤드를 추가할수록 전체 처리량이 증가함; 데이터가 잘 분산되어 있다면 여러 샤드가 동시에 쿼리를 처리할 수 있어, 전반적인 응답 시간이 단축됨
  • 저장 용량의 유연한 확장: 샤드 개수를 늘리면 전체 용량을 늘리는 효과가 있음 i.g. 샤드 하나의 저장 공간이 4TB라면, 새로 샤드를 추가할 때마다 전체 저장 용량이 4TB씩 늘어남
  • Zone 샤딩을 통한 데이터의 지역성 확보: 데이터베이스를 여러 지역에 분산 배치할 수 있어 글로벌 분산 애플리케이션에 매우 적합함

 

5. 데이터 분산

  • 샤딩된 몽고DB 클러스터에는 데이터를 적절하게 분산하는 것이 매우 중요함
  • 데이터가 효율적으로 분산되어 있을 때 작업 부하가 균형을 이루고, 전반적인 시스템 성능이 향상되며, 확장성도 높아짐

 

5.1 샤드 키

  • 몽고DB는 컬렉션 단위로 샤딩을 수행하여 사용자가 원하는 컬렉션을 선택적으로 샤딩할 수 있는데 이때 샤드 키의 선택이 매우 중요함
  • 부적절한 샤드 키 선택은 데이터 분배의 비효율성, 샤드 간 불균형한 부하, 그리고 쿼리 성능 저하를 초래할 수 있음
    • 이러한 문제로 인해 일부 샤드에만 과도한 부하가 집중되고 다른 샤드는 충분히 활용되지 못할 수 있음
    • 심각한 경우에는 핫 샤드라고 불리는 특정 샤드에 병목현상이 발생하여 클러스터 전체의 성능에 심각한 영향을 미칠 수 있음

 

  • 몽고DB는 하나 이상의 문서 필드로 구성된 샤드 키를 사용하여 컬렉션의 문서들을 여러 샤드에 분산시킴
    • 이때 데이터는 샤드 키값의 범위에 따라 청크라는 겹치지 않는 단위로 분할되며, 이러한 청크들을 클러스터의 샤드들 사이에 균등하게 분배하여 효율적인 데이터 분산을 달성함

 

5.2 샤딩 전략

몽고DB는 데이터를 분산하기 위해 두 가지 샤딩 전략을 제공합니다.


가. 범위 기반 샤딩 (default)

  • 샤드 키 값을 기준으로 데이터를 연속적인 범위로 나눔
  • 해당 방식에서는 비슷한 샤드 키 값을 가진 문서들이 동일한 샤드나 청크에 위치할 가능성이 높아, 연속적인 범위의 데이터를 조회할 때 효율적
  • 범위 기반 샤딩이 최적의 성능을 발휘하기 위해서는 샤드 키가 다음과 같은 특성을 가져야 함
    • 높은 카디널리티: 샤드 키의 카디널리티는 생성할 수 있는 청크 수의 상한을 결정하며 카디널리티가 높은 샤드 키를 선택해야 클러스터의 수평적 확장이 효율적으로 이루어짐
    • 낮은 빈도: 특정 샤드 키 값이 데이터에서 자주 반복되면, 해당 값을 가진 문서들이 모여 있는 청크가 병목 지점이 될 수 있음
    • 비단조 증감 값: 점진적으로 증가하거나 감소하는 값을 샤드 키로 사용하면 삽입 작업이 단일 청크에 집중될 수 있음

 

나. 해시 기반 샤딩

  • 샤드 키 필드값의 해시 값을 계산하여 각 청크에 할당하며 해당 방식에서는 샤드 키 값이 비슷하더라도 해시 값이 다르면 서로 다른 청크에 배치될 가능성이 높음
  • 해시 샤딩은 범위 기반 샤딩과 달리 연속적인 범위의 데이터를 조회할 때는 효율적이지 않지만 ObjectId나 타임스탬프처럼 단조증가하는 필드를 샤드 키로 사용할 때 적합한 방식

 

  • 몽고DB 4.4 버전부터는 단일 해시 필드를 포함하는 복합 인덱스를 생성할 수 있음
    • 복합 해시 인덱스를 만들려면 인덱스 생성 시 특정 인덱스 키 값을 hashed로 지정하면 됨
    • 이러한 복합 해시 인덱스는 복합 인덱스 내의 한 필드에 관해서만 해시 값을 계산하며 이렇게 계산된 값은 인덱스의 다른 필드들과 함께 샤드 키로 활용됨


 

부연 설명

  • 위 명령을 통해 planets 컬렉션에 관해 name 필드는 오름차순으로, _id 필드는 해시 값으로 구성된 복합 해시 인덱스가 생성되며, 이를 기반으로 샤딩이 수행됨

 

5.3 샤드 키 인덱스

  • 이미 데이터가 저장된 컬렉션에 관해 샤딩을 적용하려면, 해당 컬렉션에 샤드 키로 시작하는 인덱스가 반드시 존재해야 함
  • 반면, 비어 있는 컬렉션을 샤딩할 때 좀 더 유연한데 이때는 지정된 샤드 키에 맞는 인덱스가 없더라도 몽고DB가 자동으로 필요한 지원 인덱스를 생성해 줌

 

6. 청크

  • 몽고DB는 샤딩된 데이터를 청크 또는 범위라고 불리는 개별 단위로 관리됨
    • 몽고DB 5.2 버전부터는 청크의 기본 크기가 128MB로 설정되어 있으며, 이전 버전에서는 64MB였음
    • 각 청크는 샤드 키를 기준으로 하한값과 상한값이 정해지며, 특정 샤드 내에서 연속된 샤드 키 값들을 포함함
    • 이전 버전에서는 청크의 크기가 설정된 최대 크기를 초과하면 자동 분할 기능이 지원됐지만 6.1 버전부터는 자동 분할 기능이 제거되는 대신 청크가 서로 다른 샤드 간에 이동될 때만 분할이 이루어지도록 수정됨

 

6.1 밸런서와 균일한 청크 분해

  • 몽고DB 6.0.3 버전부터는 샤딩 클러스터의 데이터 분산 기준이 청크의 수가 아닌 실제 데이터의 크기로 변경됨
    • 이러한 데이터 분산을 관리하기 위해 밸런서라는 백그라운드 프로세스가 자동하며, 이는 모든 샤딩된 컬렉션에 관해 각 샤드의 데이터 용량을 모니터링하고 필요에 따라 청크를 재배치함

 

  • 밸런서는 구성 서버 복제본 세트의 주 서버에서 실행되며 해당 과정은 사용자나 애플리케이션 계층에서는 보이지 않지만, 실행 중에 시스템 성능에 약간의 영향을 끼칠 수 있음
  • 밸런서는 다음과 같은 방식으로 성능 영향을 최소화시킴
    • 각 샤드는 한 번에 하나의 마이그레이션에만 참여할 수 있음; 밸런서는 데이터 마이그레이션을 차례대로 수행하며 n개의 샤드로 구성된 클러스터에는 최대 n/2개의 동시 마이그레이션이 가능함
    • 특정 컬렉션에서 데이터가 가장 많은 샤드와 가장 적은 샤드 간의 차이가 마이그레이션 임곗값에 도달할 때만 밸런싱을 시작; 샤드 간 데이터 차이가 청크 크기의 3배 미만일 경우 해당 컬렉션은 균형이 잡힌 것으로 간주함
    • 운영 환경에서는 서비스 영향을 최소화하기 위해 밸런서 윈도라고 불리는 특정 시간대를 지정하여 밸런서의 작동 시간을 제한할 수 있음

 

7. 청크 관리

  • 특정 상황에서는 청크를 수동으로 관리해야 할 필요가 있음

 

7.1 점보 청크

  • 몽고DB에서는 지정된 크기를 초과하면서도 자동으로 분할이 불가능한 청크를 jumbo 상태로 분류함
  • 일반적으로 몽고DB가 청크의 분할과 밸런싱을 자동으로 관리하지만, 점보 청크의 경우에는 수동 개입이 필요한 상황이 발생할 수 있음
    • 청크의 점보 플래그를 제거하는 가장 권장되는 방법은 해당 청크를 분할하는 것
    • 청크 분할이 가능한 경우 몽고DB는 분할 작업을 수행한 뒤 자동으로 점보 플래그를 제거함
    • 이러한 점보 청크 분할을 위해 sh.splitAt() 또는 sh.splitFind() 메서드를 활용할 수 있음

 

7.2 나눌 수 없는 청크

  • 몽고DB에서는 단일 샤드 키값의 범위만을 가진 청크와 같이 특정 상황에서 더 이상 점보 상태가 아닌 청크도 분할이 불가능할 수 있음
  • 위와 같은 케이스에서는 청크를 나누어 점보 플래그를 제거할 수 없지만 두 가지 해결 방안이 있음
    • 샤드 키를 수정하여 청크를 분할 가능하게 하거나 (컬렉션 재샤딩)
    • 점보 플래그를 수동으로 제거하는 것

 

  • 점보 플래그를 수동으로 제거하려면 admin 데이터베이스에서 clearJumboFlag 명령을 실행해야 하며 이때 샤딩된 컬렉션의 네임스페이스와 함께 다음 중 하나를 지정해야 함


 

7.3 범위 사전 분할

  • 샤딩 클러스터는 대부분은 자동으로 데이터 범위를 생성, 분할 및 할당하므로 수동 관리가 필요하지 않지만 때로는 몽고DB가 충분한 범위를 생성하지 못하거나, 필요한 처리량만큼의 속도로 데이터를 분산시키지 못하는 상황이 발생할 수 있음
  • 특히 새로운 샤딩 클러스터에 대용량 데이터를 올릴 때는 사전 분할 전략이 유용할 수 있음
    • 해당 방법을 통해 처음부터 데이터를 모든 샤드에 균등하게 분산시킬 수 있으며, 특정 샤드에 과도한 부하가 집중되어 발생하는 병목현상을 예방할 수 있음

 

  • 빈 범위를 수동으로 나누기 위해서는 split 명령을 사용할 수 있으며 해당 명령은 샤딩 클러스터에서 하나의 청크를 두 개의 독립된 청크로 나눔
    • 이때 split 명령은 반드시 admin 데이터베이스에서 실행해야 함
    • 아래 예제는 myapp.products 컬렉션에서 price 필드를 샤드 키로 사용하고 있고, 이를 네 개의 서로 다른 가격 구간으로 사전에 나누는 코드


 

  • 몽고DB 6.0부터는 밸런서가 데이터의 실제 크기를 기준으로 샤드 간 분배를 수행하므로 위 예제처럼 단순히 범위를 나누는 것만으로는 데이터가 각 샤드에 균등하게 분산된다고 보장할 수 없음
    • 실제로 균형 잡힌 데이터 분산을 이루기 위해서는 청크를 수동으로 이동시켜야 할 수 있음


 

8. 샤딩된 데이터 쿼리하기

  • 몽고DB의 샤딩 클러스터에서 데이터를 조회하는 방식은 단일 서버나 복제본 세트에서의 조회 방식과는 차이가 있음
    • 단일 서버나 복제본 세트의 주 서버에 직접 연결하는 대신, mongos라는 쿼리 라우터에 연결하여 데이터를 요청함
    • mongos는 요청된 데이터가 어떤 샤드에 있는지 판단하고 쿼리를 적절한 위치로 라우팅하는 임무를 수행

 

8.1 mongos 라우터

  • mongos 인스턴스는 몽고DB 클러스터의 단일 접점 임무를 수행함
    • 애플리케이션은 개별 샤드에 직접 연결하지 않고 mongos를 통해 클러스터와 통신하며, mongos는 쿼리를 실행하고 결과를 취합하여 애플리케이션에 전달함
    • mongos는 상태를 저장하지 않는 가벼운 프로세스로 시스템 자원을 많이 사용하지 않는다는 장점이 있음
    • 주요 역할은 쿼리 요청을 프록시하는 것으로, 수신된 쿼리를 분산하여 적절한 샤드를 선택하고 해당 샤드에 커서를 설정함

 

8.2 find

  • 쿼리에 샤드 키나 샤드 키의 접두사가 포함되어 있다면, mongos는 대상이 되는 샤드만을 선택적으로 쿼리하는 표적화된 작업을 수행함
    • 쿼리가 샤드 키의 접두사 혹은 완전한 샤드 키를 포함할 경우, mongos는 해당 데이터가 있는 특정 샤드만을 대상으로 쿼리를 수행함
    • 반면, 샤드 키에 포함되지 않는 필드를 대상으로 쿼리 할 경우 적절한 샤드를 특정할 수 없어 모든 샤드를 대상으로 브로드캐스팅 쿼리를 수행하는데 이를 스캐터-개더 작업 또는 팬아웃 쿼리라고도 함

 

8.3 sort(), limit(), skip()

  • 결과를 정렬할 때는 다음과 같은 두 가지 방식을 선택할 수 있음
    • 샤드 키를 정렬 기준으로 사용하면, mongos가 쿼리할 샤드의 순서를 효율적으로 결정하여 최적화된 작업을 수행할 수 있음
    • 샤드 키가 아닌 다른 기준으로 정렬하면 팬아웃 쿼리가 발생하며 이 경우 주 샤드는 mongos에 정렬된 결과를 전달하기 전에 로컬에서 분산 병합 정렬을 수행함

 

  • 쿼리의 limit은 개별 샤드와 mongos 단계에서 각각 적용되는데 이는 여러 샤드에서 결과가 반환될 수 있기 때문
  • 반면 skip 연산은 개별 샤드에 전달되지 않고, mongos가 모든 결과를 로컬에서 확인한 후 적용됨
  • skip()과 limit() 커서 메서드를 함께 사용하면 mongos가 이 두 값을 개별 샤드에 전달하여 쿼리를 최적화시키며 이는 페이지네이션 구현에 특히 유용함

 

8.4 수정과 삭제

  • 몽고DB 7.0 버전부터는 update, delete와 같은 문서 수정 작업의 처리 방식이 단순화됨
  • 쿼리의 find() 부분에서 샤드 키가 포함된 경우, mongos는 기존처럼 해당 샤드로 쿼리를 직접 전달하지만 find 부분에 샤드 키가 없더라도 이전 버전과 달리 팬아웃 작업이 발생하지 않음
  • updateOne(), deleteOne(), findAndModify() 작업을 수행할 때도 더 이상 샤드 키나 _id 값을 필수적으로 포함할 필요가 없음
    • 샤딩되지 않은 컬렉션처럼 어떤 필드로도 문서를 검색할 수 있게 되었음
    • 다만, 샤드 키를 사용하면 표적화된 쿼리가 가능해 더 효율적인 처리가 가능함

 

8.5 헤지 읽기 (hedge read)

  • 몽고DB 4.4 버전부터 mongos 인스턴스는 헤지 읽기라는 기능을 통해 비주요 읽기 선호도를 활용할 수 있음
    • 해당 기능을 사용하면 mongos 인스턴스가 쿼리가 필요한 각 샤드의 복제본 세트에서 두 구성원에게 동시에 읽기 작업을 요청하고, 각 샤드에서 가장 먼저 응답한 결과를 반환함
    • 헤지 읽기 지원하는 작업에는 collStats, count, dataSize, dbStats, distinct, filemd5, find, listCollections, listIndexes, planCacheListFilters가 포함됨

 

9. 샤딩 메서드

  • 몽고DB는 데이터 분산 관리를 위한 다양한 도우미 메서드를 제공하고 있으며 이러한 메서드들은 샤딩 활성화, 데이터 분산 방식 정의, 샤딩, 상태 모니터링 등에 활용됨
  • sh.shardCollection()은 몽고DB에서 샤딩을 설정하는 데 필수적인 메서드
    • 컬렉션이 한번 샤딩되면 몽고DB는 이를 되돌리는 방법을 제공하지 않지만
    • 필요한 경우 추후 샤드 키 변경은 가능함

 

  • db.collection.getShardDistribution()은 특정 샤딩된 컬렉션의 샤드 간 데이터 분포에 관한 상세 정보를 제공하며 해당 명령어의 출력 정보는 다음과 같음

 

출력 종류 설명
<shard-x> 문자열 샤드 이름을 보유
<host-x> 문자열 호스트 이름을 보유
<size-x> 숫자 측정 단위를 포함한 데이터의 크기를 포함
<count-x> 숫자 샤드에 있는 문서 수를 보고
<numberof chunks-x> 숫자 샤드의 청크 수를 보고
<size-x>
/
<numberof chunks-x>
계산된 값 샤드의 청크당 예상 데이터 크기를 반영
<count-x>
/
<numberofchunks-x>
계산된 값 샤드에 관한 청크당 예상 문서 수를 반영
<stats.size> 숫자 측정 단위를 포함하여 샤드된 컬렉션에 있느 데이터와 총 크기를 보고
<stats.count> 숫자 샤드된 컬렉션의 문서 총수를 보고
<calctotallchunks> 계산된 값 모든 샤드의 청크 수를 보고
<estDataPercent-x> 계산된 값 각 샤드의 예상 데이터의 크기를 컬렉션의 전체 데이터 크기 대비 백분율로 나타냄
<estDocPercent-x> 계산된 값 각 샤드의 예상 문서 수를 컬렉션의 문서 총수에 관한 백분율로 반영

 

 

  • sh.status()는 샤딩 클러스터의 정보를 제공함
    • verbose 매개변수를 통해 출력의 상세 수준을 조정할 수 있어 개요나 상세 보고서 중 선택이 가능함
    • 해당 명령어는 샤딩 버전, 각 샤드의 세부 정보, 활성 mongos 인스턴스 상태, 자동 분할 상태, 밸런서 상태 그리고 데이터베이스와 샤딩된 컬렉션 정보를 포함

 

  • sh.getBalancerState()는 현재 밸런서의 활성 상태를 나타내는 불리언 값을 반환
  • 집계 단계에서 $shardedDataDistribution은 샤딩 클러스터의 데이터 분포 정보를 반환
  • 몽고DB 5.0 버전부터는 sh.reshardCollection() 메서드를 통해 컬렉션의 샤드 키를 수정하여 클러스터 전반의 데이터 분산 방식을 변경할 수 있음
    • 단, 재샤딩 작업 전에는 애플리케이션이 2초간의 쓰기 차단을 허용할 수 있는지 확인해야 함
    • 또한 데이터베이스 서버에 스토리지, I/O, CPU 사용량과 같은 필수 자원이 갖춰져야 함

 

몽고DB 7.0 버전의 새로운 샤딩 클러스터 기능

  • 몽고DB 7.0 버전은 운영과 개발자 사용 사례 면에서 샤딩 클러스터의 관리와 이해를 더욱 단순화했음
    • 해당 버전에서는 초기 및 향후 샤드 키 선택 시 최적의 의사결정을 돕은 추가 인사이트를 제공
    • 또한 개발자가 샤딩 클러스터와 일반 클러스터에서 명령어를 사용할 때 일관된 인터페이스를 경험할 수 있으며, 필요한 경우 성능 최적화 옵션도 유지할 수 있음

 

1. 샤드 키 조언자 명령어

  • 몽고DB 7.0 버전의 신규 기능들은 복잡한 데이터 패턴과 상충 관계로 인해 까다로웠던 샤드 키 선택 과정을 간소화하는 데 중점을 둠
    • analyzeShardKey는 기존 데이터를 기반으로 후보 샤드 키를 평가할 수 있게 해주며 몽고DB 7.0의 샤드 키 분석은 고유성, 빈도, 단조성 등의 지표를 통해 샤드 키의 적합성을 평가함
    • configureQueryAnalyzer는 클러스터 전반의 쿼리 라우팅 패턴에 관한 지표를 제공하여 불균형한 부하와 과부하 샤드를 식별하는 데 도움을 주며 해당 명령어는 기존 구성과 새로운 구성을 설명하는 필드들이 포함된 문서를 반환함; 이러한 두 명령어를 통해 초기 샤드 키를 설정하거나 실시간 리샤딩을 준비할 때 필요한 데이터를 바탕으로 더욱 확신 있는 의사결정이 가능해짐
    • mergeAllChunksOnShard 명령어는 특정 샤드가 보유한 컬렉션의 모든 병합할 수 있는 데이터 청크를 통합하도록 설계되었으며 이는 특정 샤드에서 병합할 수 있는 모든 청크를 찾아 병합함으로써 샤딩 유지보수 작업 중 발생하는 성능 저하 문제를 해결함; 이를 통해 쿼리 대상 청크의 수를 줄여 단편화를 감소시키고 성능을 향상할 수 있음

 

2. AutoMerger

  • AutoMerger는 특정 병합 가능성 요구사항을 충족하는 청크들을 자동으로 병합하는 기능이며 프로세스는 밸런싱 작업의 하나로 백그라운드에서 실행됨
  • AutoMerger는 비활성화되지 않는 한 밸런서가 처음 활성화될 때 시작되며 각 실행 후 설정된 간격 (autoMergerIntervalSecs)동안 일시 중지됨
    • 활성화 상태에서는 정해진 간격마다 자동 병합을 수행하며, 각 컬렉션에 관해 연속적인 병합 사이에 최소 지연 시간 (autoMergerThrottlingMS)을 보장

 

  • 동일한 컬렉션 내의 두 개 이상의 연속된 청크는 다음 조건을 모두 충족할 때 병합이 가능함
    • 동일한 샤드에 속할 것
    • 점보 청크가 아닐 것 (점보 청크는 마이그레이션 불가)
    • 트랜잭션이나 스냅샷 읽기를 방해하지 않고 안전하게 제거할 수 있는 마이그레이션 기록을 가질 것

 

3. 샤드 키 없는 명령어 지원

  • 몽고DB 7.0부터는 updateOne, deleteOne, findAndModify 등의 명령어들이 샤딩 클러스터와 일반 클러스터 모두에서 일관되게 작동하며 필요한 경우에는 성능 최적화를 위한 옵션도 함께 제공됨

 

참고

마스터링 몽고DB 7.0

반응형

'DB > 마스터링 몽고DB 7.0' 카테고리의 다른 글

[7장] 몽고DB 고급 쿼리  (0) 2025.07.15
[6장] 스키마 설계와 데이터 모델링  (1) 2025.07.11
[5장] CRUD 작업과 기본 쿼리  (1) 2025.07.11
[4장] 몽고DB 연결  (0) 2025.07.11
[3장] 개발자 도구  (0) 2025.07.10