복제 (Replication)
복제 (Replication)
MongoDB에서 replica set(레플리카 셋) 이란, 동일한 데이터 셋을 유지하는 mongod 프로세스들의 그룹이에요. 레플리카 셋은 중복성(redundancy)과 고가용성(high availability)을 제공하며, 모든 프로덕션 배포의 기반이 됩니다.
이 섹션에서는 MongoDB의 복제와 레플리카 셋의 구성 요소·아키텍처를 소개하고, 레플리카 셋과 관련된 일반적인 작업을 위한 튜토리얼도 함께 제공해요.
MongoDB Atlas에 호스팅된 배포는 UI에서 레플리카 셋을 배포할 수도 있습니다.
중복성과 데이터 가용성 (Redundancy and Data Availability)
복제는 데이터 가용성(data availability)과 중복성을 제공해요. 데이터베이스 서버들에 데이터의 여러 복사본을 유지함으로써, 어떤 단일 서버 하나가 손실돼도 전체 시스템이 계속 동작할 수 있게 만드는 거죠.
MongoDB에서의 복제
레플리카 셋은 동일한 데이터 셋을 유지하는 mongod 인스턴스들의 그룹이에요. 레플리카 셋은 여러 개의 데이터 보유(data bearing) 노드와, 선택적으로 하나의 아비터(arbiter) 노드를 포함합니다.
경고:
각 레플리카 셋 노드는 반드시 하나의(그리고 오직 하나의) 레플리카 셋에만 속해야 해요. 레플리카 셋 노드는 둘 이상의 레플리카 셋에 속할 수 없습니다.
프라이머리 노드(primary node)는 모든 쓰기 연산을 받습니다.
레플리카 셋에는 { w: "majority" } write concern으로 쓰기를 확인(confirm)할 수 있는 프라이머리가 오직 하나만 있을 수 있어요. 다만 일부 상황에서는 다른 mongod 인스턴스가 자신도 프라이머리라고 일시적으로(transiently) 믿을 수는 있습니다.
프라이머리는 자신의 데이터 셋에 대한 모든 변경 사항을 operation log, 즉 oplog에 기록해요. 프라이머리 노드 동작에 대한 자세한 내용은 레플리카 셋 프라이머리(Replica Set Primary)를 참고하세요.
세컨더리(secondaries)는 프라이머리의 oplog를 복제하고, 그 연산들을 자신의 데이터 셋에 적용해서 세컨더리의 데이터 셋이 프라이머리의 데이터 셋을 반영하도록 만듭니다.
프라이머리를 사용할 수 없게 되면, 자격을 갖춘 세컨더리가 선거(election)를 열어 새로운 프라이머리를 선출해요. 세컨더리 멤버에 대한 자세한 내용은 레플리카 셋 세컨더리 멤버(Replica Set Secondary Members)를 참고하세요.
비용 제약 때문에 세컨더리를 하나 더 추가할 수 없다면, mongod 인스턴스를 아비터(arbiter)로 레플리카 셋에 추가할 수 있어요.
아비터는 선거(elections)에는 참여하지만 데이터를 보유하지는 않습니다(즉, 데이터 중복성을 제공하지 않아요). 아비터에 대한 자세한 내용은 레플리카 셋 아비터(Replica Set Arbiter)를 참고하세요.
아비터는 항상 아비터로 남지만, 프라이머리는 스텝다운(step down)해서 세컨더리가 될 수 있고, 세컨더리는 선거 중에 프라이머리가 될 수도 있습니다.
비동기 복제 (Asynchronous Replication)
세컨더리는 프라이머리의 oplog를 복제하고 그 연산들을 비동기적으로(asynchronously) 자신의 데이터 셋에 적용해요. 세컨더리의 데이터 셋이 프라이머리의 데이터 셋을 반영하도록 유지함으로써, 하나 이상의 멤버가 실패해도 레플리카 셋은 계속 기능할 수 있습니다.
복제 메커니즘에 대한 자세한 내용은 레플리카 셋 Oplog와 레플리카 셋 데이터 동기화를 참고하세요.
느린 연산 (Slow Operations)
느린 연산은 다음의 특징을 가져요.
- 세컨더리의 경우
diagnostic log에 기록됩니다. REPL컴포넌트 아래에applied op: <oplog entry> took <num>ms텍스트로 기록됩니다.- 로그 레벨(시스템 또는 컴포넌트 레벨)에 의존하지 않습니다.
- 프로파일링(profiling) 레벨에 의존하지 않습니다.
slowOpSampleRate의 영향을 받습니다.
복제 지연과 플로우 컨트롤 (Replication Lag and Flow Control)
복제 지연(replication lag)은 프라이머리에서의 연산과, 그 연산이 oplog에서 세컨더리로 적용되는 시점 사이의 지연이에요. 작은 지연은 어느 정도 허용될 수 있지만, 복제 지연이 커지면 프라이머리에서 캐시 압력(cache pressure)이 쌓이는 등 심각한 문제가 발생합니다.
관리자는 majority committed 지연을 구성 가능한 최대값인 flowControlTargetLagSeconds 아래로 유지하는 것을 목표로, 프라이머리가 쓰기를 적용하는 비율을 제한할 수 있어요.
기본적으로 플로우 컨트롤(flow control)은 활성화(enabled)되어 있습니다.
플로우 컨트롤이 활성화되면, 지연이 flowControlTargetLagSeconds에 가까워질수록, 프라이머리의 쓰기는 락(lock)을 잡고 쓰기를 적용하기 전에 티켓(ticket)을 획득해야 해요.
플로우 컨트롤 메커니즘은 초당 발급되는 티켓 수를 제한함으로써 지연을 목표값 아래로 유지하려고 시도합니다.
자세한 내용은 복제 지연 확인과 플로우 컨트롤을 참고하세요.
자동 페일오버 (Automatic Failover)
프라이머리가 구성된 electionTimeoutMillis 기간(기본값 10초)보다 오랫동안 셋의 다른 멤버와 통신하지 못하면, 자격을 갖춘 세컨더리가 선거를 열어 자신을 새 프라이머리로 지명합니다.
기본 레플리카 구성 설정(replica configuration settings)을 가정할 때, 클러스터가 새 프라이머리를 선출하기까지의 중앙값(median) 시간은 일반적으로 12초를 넘지 않아야 해요.
여기에는 프라이머리를 사용 불가(unavailable)로 표시하는 데 필요한 시간과, 선거(election)를 호출하고 완료하는 데 필요한 시간이 포함됩니다.
이 시간은 settings.electionTimeoutMillis 레플리카 구성 옵션을 수정해서 조정할 수 있어요.
기본값 10000(10초)에서 electionTimeoutMillis 레플리카 구성 옵션을 낮추면 프라이머리 장애를 더 빨리 감지할 수 있습니다.
호환 가능한 드라이버는 기본적으로 재시도 가능한 쓰기(retryable writes)를 활성화합니다.
MongoDB는 미러링된 읽기(mirrored reads)를 제공해서, 선출 가능한(electable) 세컨더리 멤버의 캐시를 가장 최근에 접근한 데이터로 미리 워밍(pre-warm)해요. 세컨더리의 캐시를 미리 워밍하면 선거 후 성능을 더 빠르게 복원하는 데 도움이 됩니다.
관련 주제:
- 레플리카 셋 선거 (Replica Set Elections)
- 재시도 가능한 쓰기 (Retryable Writes)
- 레플리카 셋 페일오버 중 롤백 (Rollbacks During Replica Set Failover)
읽기 연산 (Read Operations)
읽기 선호도 (Read Preference)
기본적으로 클라이언트는 프라이머리에서 읽습니다. 하지만 클라이언트는 읽기 선호도(read preference)를 지정해서 읽기 연산을 세컨더리로 보낼 수도 있어요.
세컨더리로의 비동기 복제는 세컨더리에서의 읽기가 프라이머리의 데이터 상태를 반영하지 않는 데이터를 반환할 수 있음을 의미해요.
읽기 연산을 포함하는 트랜잭션(Transactions)은 반드시 읽기 선호도 primary를 사용해야 합니다. 주어진 트랜잭션의 모든 연산은 동일한 멤버로 라우팅되어야 해요.
레플리카 셋에서의 읽기에 대한 내용은 읽기 선호도(Read Preference)를 참고하세요.
데이터 가시성 (Data Visibility)
읽기 고려(read concern)에 따라, 클라이언트는 쓰기가 durable(영구화)되기 전에 쓰기 결과를 볼 수 있습니다.
다중 문서 트랜잭션(multi-document transaction)의 연산에서는, 트랜잭션이 커밋되면 트랜잭션에서 이루어진 모든 데이터 변경이 저장되고 트랜잭션 외부에서도 보입니다. 즉, 트랜잭션은 일부 변경만 커밋하고 다른 변경은 롤백하지 않습니다.
MongoDB의 읽기 격리(isolation), 일관성(consistency), 최신성(recency)에 대한 자세한 내용은 읽기 격리, 일관성, 최신성 (Read Isolation, Consistency, and Recency)을 참고하세요.
미러링된 읽기 (Mirrored Reads)
미러링된 읽기는 페일오버가 발생하기 전에 electable 세컨더리 레플리카 셋 멤버의 캐시를 미리 워밍해서, 프라이머리 선거의 영향을 줄여줘요.
프라이머리는 자기가 받은 지원되는 연산(supported operations)의 샘플을 선출 가능한 세컨더리로 미러링합니다.
미러링된 읽기를 받는 electable 세컨더리 레플리카 셋 멤버의 부분 집합 크기는 mirrorReads 파라미터로 구성할 수 있어요.
타겟 미러링된 읽기 (Targeted Mirrored Reads)
MongoDB 8.2부터 노드에 태그를 지정해서 읽기 미러링을 위한 캐시 워밍이 필요한 특정 서버에 읽기 연산을 선택적으로 미러링할 수 있어요. 일반적인 미러링된 읽기와 달리, 타겟 읽기 미러링은 숨겨진(hidden) 노드를 대상으로 할 수 있고 프라이머리와 세컨더리 노드 모두에서 미러링할 수 있습니다.
타겟 미러링된 읽기는 mirrorReads 파라미터의 targetedMirroring 필드를 사용해서 구성할 수 있어요.
지원되는 연산 (Supported Operations)
findAndModify(구체적으로는, 필터(filter)가 미러링된 읽기로 전송됩니다)update(구체적으로는, 필터(filter)가 미러링된 읽기로 전송됩니다)
미러링된 읽기 지원 활성화/비활성화
미러링된 읽기는 기본적으로 활성화되어 있으며 기본 샘플링 비율(sampling rate)은 0.01이에요.
미러링된 읽기를 비활성화하려면 mirrorReads 파라미터를 { samplingRate: 0.0 }로 설정하세요:
db.adminCommand( {
setParameter: 1,
mirrorReads: { samplingRate: 0.0 }
} )
샘플링 비율이 0.0보다 크면, 프라이머리는 지원되는 읽기를 electable 세컨더리의 일부로 미러링해요.
샘플링 비율이 0.01이면, 프라이머리는 받은 지원되는 읽기의 1퍼센트를 선출 가능한 세컨더리 일부로 미러링합니다.
예를 들어, 프라이머리 하나와 선출 가능한 세컨더리 둘로 구성된 레플리카 셋을 생각해 보죠. 프라이머리가 미러링 가능한 연산을 1000개 받고 샘플링 비율이 0.01이라면, 프라이머리는 무작위로 선택된 선출 가능한 세컨더리 일부로 약 10개의 지원되는 읽기를 미러링해요.
미러링된 읽기의 샘플링 비율 변경
미러링된 읽기의 샘플링 비율을 변경하려면 mirrorReads 파라미터를 0.0과 1.0 사이의 숫자로 설정하세요:
- 샘플링 비율
0.0은 미러링된 읽기를 비활성화합니다. 0.0과1.0사이의 샘플링 비율은 프라이머리가 지원되는 읽기의 무작위 샘플을 지정된 비율로 선출 가능한 세컨더리로 전달하게 합니다.- 샘플링 비율
1.0은 프라이머리가 모든 지원되는 읽기를 선출 가능한 세컨더리로 전달하게 합니다.
자세한 내용은 mirrorReads를 참고하세요.
트랜잭션 (Transactions)
다중 문서 트랜잭션(multi-document transactions)은 레플리카 셋에서 사용할 수 있어요.
읽기 연산을 포함하는 트랜잭션은 반드시 읽기 선호도 primary를 사용해야 합니다. 주어진 트랜잭션의 모든 연산은 동일한 멤버로 라우팅되어야 해요.
예를 들어, 어떤 트랜잭션이 커밋되었는데 쓰기 1은 샤드 A에서 보이지만 쓰기 2는 아직 샤드 B에서 보이지 않는다면, 읽기 고려 "local"의 외부 읽기는 쓰기 2를 보지 못한 채 쓰기 1의 결과를 읽을 수 있습니다.
변경 스트림 (Change Streams)
변경 스트림(change streams)은 레플리카 셋과 샤딩된 클러스터에서 사용할 수 있어요. 변경 스트림을 사용하면 애플리케이션은 oplog를 테일링(tailing)하는 복잡성과 위험 없이 실시간 데이터 변경에 접근할 수 있습니다.
추가 기능 (Additional Features)
예를 들어, 레플리카 셋을 여러 데이터 센터에 걸친 멤버들로 배포할 수 있고, 일부 멤버의 members[n].priority를 조정해서 선거 결과를 제어할 수도 있어요. 레플리카 셋은 리포팅(reporting), 재해 복구(disaster recovery), 또는 백업 기능을 위한 전용 멤버도 지원합니다.
자세한 내용은 Priority 0 레플리카 셋 멤버, 숨겨진 레플리카 셋 멤버(Hidden Replica Set Members), 지연된 레플리카 셋 멤버(Delayed Replica Set Members)를 참고하세요.
일부 상황에서는 레플리카 셋의 두 노드가 일시적으로(transiently) 자신이 프라이머리라고 믿을 수 있지만, 최대 하나만이 { w: "majority" }로 쓰기를 완료할 수 있습니다.
{ w: "majority" } 쓰기를 완료할 수 있는 노드가 현재 프라이머리이고, 다른 노드는 자신의 강등(demotion)을 아직 인식하지 못한 이전 프라이머리이며, 일반적으로 네트워크 파티션(network partition) 때문이에요.
이런 경우, 이전 프라이머리에 연결한 클라이언트는 읽기 선호도 primary를 요청했음에도 불구하고 지연된(stale) 데이터를 관찰할 수 있고, 이전 프라이머리에 대한 새 쓰기는 결국 롤백됩니다.