몽고디비 11장 - 복제 셋 구성요소
11. 복제 셋 구성요소
11.1 동기화
- 로그, 즉 oplog를 보관함으로써 복제를 수행한다.
Replica Set Oplog 네이밍이다.
Oplog는 Replica set의 데이터를 동기화를 위해 내부에서 발생하는 모든 동작의 로그를 기록한 것 이다.
- 세컨더리 다운되면 재시작할 때 oplog에 있는 마지막 연산과 동기화한다.
- oplog 작업은 멱등이다. (동일한 데이터 결과셋)
- 크기가 고정되어 있어서 연산의 수가 정해져있다.
- 기본크기로 괜찮다.
- 다만, 삭제만 oplog 여러개 항목으로 분해된다.
- 예를 들어서 db.col.remove() 로 도큐먼트 100만개를 삭제하면 oplog 항목 100만개를 하나씩 삭제한다.
아래의 케이스의 경우 기본 oplog크기보다 더 크게 줘야하는 케이스가 된다.
한 번에 여러 도큐먼트 갱신
- oplog의 멱등성을 유지하기 위해 다중갱신을 개별 작업으로 변환해야 한다.
- 각의 작업이 독립적이며 그 자체로 완전한 결과를 낼 수 있도록 설계되어야 하고, 그 결과가 여러 번 수행되어도 변경되지 않아야 한다는 것을 의미
삽입한 데이터와 동일한 양의 데이터 삭제
- 삭제에서 디스크 사용량 측면은 크게 증가하지 않지만 oplog 크기는 클 수 있다.
상당한 수의 내부 갱신
- 크기를 증가시키지 않는 갱신이라면 데이터베이스에 기록되는 작업의 수는 많지만 디스크 데이터 양은 변하지 않는다.
이러한 크기 조정은 mongod가 oplog를 만들기 전에 oplogSizeMB 옵션을 사용해 크기를 지정할 수 있다.
→ https://oreil.ly/mh5SX 참고 하면 좋겠다. 🙂
그러면 동기화는 어떻게 할까?
11.1.1 초기 동기화
- 복제 셋의 한 멤버에서 다른 멤버로 모든 데이터를 복사한다.
- 다만, 유효한 상태인지 확인한다.
- 만약, 유효하다면 복제셋의 다른 멤버의 데이터 전체를 복사한다.
- 이러한 프로세 단계는 mongod 로그에서 확인할 수 있다.
2023-10-01T12:00:00.123+0000 I REPL [replication-0] Starting initial sync with source: replicaSetA:27017
2023-10-01T12:00:05.456+0000 I REPL [replication-0] Initial sync data cloning for database 'testDb' started
2023-10-01T12:05:00.789+0000 I REPL [replication-0] Initial sync cloning of collection 'testDb.collection1' finished
2023-10-01T12:10:00.012+0000 I REPL [replication-0] Initial sync data cloning completed
2023-10-01T12:15:00.345+0000 I REPL [replication-0] Data consistency checks are starting
2023-10-01T12:20:00.678+0000 I REPL [replication-0] Data is consistent
2023-10-01T12:25:00.901+0000 I REPL [replication-0] Initial sync applying oplog entries
2023-10-01T12:30:00.234+0000 I REPL [replication-0] Initial sync apply phase finished
2023-10-01T12:35:00.567+0000 I REPL [replication-0] Initial sync completed successfully //초기 동기화 완료
→ 그러면, 복제는 어떤것을 하냐면?
- local 데이터베이스를 제외한 모든 데이터베이스를 복제한다.
- mongod는 각 소스 데이터베이스 내 컬렉션을 모두 스캔해서 복사하려고 하는 멤버의 컬렉션의 복사본에 삽입하게 된다.
복제를 할 때 세컨더리가 프라이머리에 있는 데이터셋과 일치해야 하는데
- 복제셋은 하나의 프라이머리 노드 하나 이상의 세컨더리 노드로 구성 (쓰기와 읽기가 구분)
- 데이터의 모든 변경사항은 oplog에 기록
- 세컨더리 노드는 자신의 로컬 oplog를 주기적으로 스캔하여, 프라이머리 노드의 최신 변경사항을 파악 (컬렉션들에 의해 복제, 데이터 일관성 보장)
- 세컨더리 노드는 프라이머리 노드에서 받은 oplog 항목을 자신의 데이터베이스에 적용
세컨더리 노드가 프라이머리 노드의 데이터셋과 일치하도록 만드는 데 필수
- 초기 동기화 과정을 완료
- 세컨더리 노드가 새로 복제 셋에 추가되면, 초기 동기화 과정이 시작됩니다. 이 과정에서 세컨더리 노드는 프라이머리 노드로부터 모든 데이터를 처음부터 복제
- 세컨더리 노드는 프라이머리 노드의 모든 데이터베이스와 컬렉션을 복사
- 데이터 복사가 완료된 후, 세컨더리 노드는 프라이머리 노드의 oplog(운영 로그)를 복사하여 시작 시점부터 현재까지의 모든 변경사항을 적용
- oplog의 모든 항목이 세컨더리 노드에 적용되면, 초기 동기화 과정이 완료
- 일반 동기화 단계로 전환
- 초기 동기화가 완료된 후, 세컨더리 노드는 프라이머리 노드의 oplog를 지속적으로 모니터링하고 복제
- 세컨더리 노드는 프라이머리 노드의 oplog를 주기적으로 확인하고, 새로운 업데이트가 있을 때마다 이를 적용하여 데이터의 일관성을 유지
- 만약 프라이머리 노드에 문제가 발생하여 사용할 수 없게 되면, 복제 셋의 세컨더리 노드 중 하나가 새로운 프라이머리 노드로 승격될
과정을 거치게 된다.
oplog
프라이머리 기록
세컨더리 동기화 안된 상태는
이러한 과정에서 데이터의 신뢰성과 가용성을 높힌다.
이러한 복제를 수행할 때 작업 셋을 망칠 수 있는데,
- 초기 동기화 과정에서 자주 사용하는 데이터는 추출하여 메모리로 페이징되는 과정에서 멤버가 급격하게 느려지게 된다.
- 램에서 디스크로 향하기 때문에
- 복사된 데이터는 처리를 위해 세컨더리 노드의 RAM(랜덤 액세스 메모리)에 로드됩니다. 자주 사용되는 데이터가 많은 경우, 메모리 사용량이 급격히 증가
- 메모리가 포화 상태에 이르면, 운영 체제는 메모리에 있는 일부 데이터를 디스크로 스왑(페이징) → 이때 램에서 디스크로 (디스크의 입출력 속도가 메모리의 속도보다 훨씬 느리기 때문에 시스템의 반응 속도가 저하)
- 페이징으로 인해 디스크 I/O가 증가하고, 이는 전체 시스템의 성능 저하로 이어진다.
- 결과적으로는… 세컨더리 노드는 데이터 처리 속도가 느려지며, 초기 동기화에 필요한 시간이 길어진다.
- 램에서 디스크로 향하기 때문에
- 그리고 시간이 오래걸린다.
11.1.2. 복제
- 세컨더리 멤버는 초기 동기화 후 지속적으로 데이터를 복제한다. (비동기로)
11.1.3. 실효처리
- 세컨더리가 만약 동기화 진행이 미흡하게 되면 실효상태가 된다.
- 세컨더리 노드가 프라이머리 노드와의 동기화를 유지하지 못하게 되어 최신 데이터의 상태를 반영하지 못하는 상황 ⇒ 데이터 일관성과 무결성에 영향을 줄 수 있음
- 아래 케이스에서 실효상태가 발생할 수 있다.
- 네트워크 장애, 유지보수로 세컨더리 노드의 다운타임
- 세컨더리 노드가 다운되어 있는 동안, 프라이머리 노드에서는 계속 데이터 변경이 일어나고 이 변경사항들이 oplog에 기록
- 세컨더리 노드가 다시 온라인이 되었을 때, 동기화해야 할 데이터 양이 너무 많아져서, oplog window(세컨더리가 복구할 수 있는 oplog의 시간 범위)를 초과할 수 있으며, 이로 인해 세컨더리가 최신 상태로 복구될 수 없음
- 프라이머리 노드의 과도한 쓰기 요청
- 과도한 쓰기 작업으로 인해 생성되는 데이터 변경 로그(oplog)의 양이 많아짐
- 세컨더리 노드는 이 모든 변경을 실시간으로 동기화하기 어려워질 수 있으며, 필요한 데이터를 놓치거나 동기화가 미흡
- 네트워크 장애, 유지보수로 세컨더리 노드의 다운타임
- 실효상태가 발생하는 원인 중 하나에는 아래 케이스로 동기화를 계속 진행하게 될 경우 일부 작업을 건너뛰게 된다. 이래서 발생하는듯?
- 세컨더리가 다운타임, 쓰기 요청이 많거나 이런 경우가 된다.
11.2 하트비트
- 멤버는 복제 셋에 대한 최신 정보를 유지하기 위해 복제 셋의 모든 멤버로 2초마다 하트비트 요청을 보낸다.
- 과반수 도달 여부로 결정하는듯?
- 결정할 수 없다면 스스로 세컨더리가 된다.
예시
- 복제 셋 구성: 복제 셋이 5개의 멤버(3개의 세컨더리와 1개의 프라이머리, 1개의 아비터)로 구성되어 있다고 가정
- 하트비트 발송: 각 멤버는 다른 모든 멤버에게 주기적으로 하트비트를 보내고. 이 신호는 멤버가 살아있고 네트워크에 연결되어 있음을 확인
- 프라이머리의 장애: 프라이머리 노드가 네트워크 장애로 인해 다른 멤버와의 연결이 끊어지면, 나머지 멤버들은 프라이머리 노드로부터 하트비트를 수신하지 못함
- 과반수 확인: 나머지 멤버들은 프라이머리 노드를 포함한 다른 멤버들로부터 과반수 이상의 하트비트 응답을 받지 못하면, 새로운 프라이머리 노드 선출을 위한 선거(election) 과정을 시작
- 선거 과정: 선거는 살아있는 멤버들 중에서 새로운 프라이머리 노드를 선출하기 위해 진행. 과반수 이상의 멤버들이 하나의 멤버에게 투표해야 새로운 프라이머리가 선출
- 과반수 도달 실패: 만약 네트워크 분할(network partition)로 인해 어떠한 그룹도 과반수에 도달하지 못한다면, 그 그룹의 멤버들은 스스로를 세컨더리 상태로 전환이 상태에서는 새로운 데이터의 쓰기가 불가능하며, 클러스터의 데이터 일관성을 유지하기 위해 읽기 전용 상태로 남음
- 복구 및 재연결: 네트워크 상태가 복구되고 멤버들이 다시 연결되면, 하트비트를 통해 멤버들의 상태를 재확인하고 필요하다면 새로운 프라이머리 선출 과정이 다시 시작
11.2.1 멤버 상태
- 멤버들은 하트비트를 통해 상태를 주고 받는다.
상태에는 다음의 것들이 있다.
- startup
- MongoDB 서버 인스턴스가 방금 시작되었고, 아직 구성을 완료하지 않은 상태
- 서버를 처음 시작할 때, 데이터베이스는 자동으로 이 상태로 설정되며, 기본 구성 및 초기화 작업을 수행
- startup2
- 데이터베이스는 초기화를 마쳤으나 아직 복제 셋의 다른 멤버들과 통신을 시작하지 않은 상태
- 초기 설정 단계에서 인덱스 구축, 기존 데이터 검사 등을 완료한 후 복제 프로세스 준비 단계
- recovering
- 이 멤버는 현재 데이터 복구 모드에 있으며, 동기화 중이거나 장애로 인해 복구 중인 상태
- 복제 셋에서 하나의 노드가 장애 후 복구 중이거나, 초기 동기화 중 발생한 문제를 해결 중일 때 이 상태를 가질 수 있음
- arbiter
- 아비터는 복제 셋에서 투표만을 수행하는 특수한 유형의 멤버로, 데이터를 저장하지 않
- 복제 셋의 멤버 수를 홀수로 유지하기 위해 아비터를 추가하여, 선거 프로세스에서 투표 권한을 갖음
- down
- 이 상태는 멤버가 네트워크에 연결되지 않거나 작동하지 않는 상태를 나타냄
- 서버 하드웨어 실패, 네트워크 문제 등으로 인해 멤버에 접근할 수 없을 때 이 상태
- unknown
- 멤버의 현재 상태를 다른 멤버들이 파악할 수 없는 경우
- 네트워크 분할로 인해 멤버 간 통신이 끊어진 경우, 다른 멤버들은 해당 멤버의 상태를 'unknown'으로 간주
- removed
- 이 멤버는 복제 셋에서 제거되었으나 아직 구성에서 완전히 삭제되지 않은 상태
- 복제 셋에서 멤버를 수동으로 제거한 후, 구성에서 이 멤버를 청소하는 작업이 진행
- rollback
- 데이터의 일관성을 유지하기 위해, 이 멤버는 데이터를 이전 상태로 되돌리는 중.
- 세컨더리 노드가 프라이머리 노드와의 동기화 과정에서 충돌이 발생했을 때, 불일치하는 데이터를 롤백하여 일관성을 회복
11.3 선출
- 멤버가 프라이머리에 도달하지 못하면 프라이머리 선출을 모색한다.
- 그리고 자격도 확인해본다. (복제에서 뒤쳐질 수 있다.)
- 데이터 동기화 상태
- 네트워크 연결 상태
- 투표권한
- oplog윈도우
- 프라이머리가 되지 못한 즉, 과반수의 동의를 얻지못한 멤버는 세컨더리가 되었다가 나중에 다시 도전한다.
- 일반적으로 프라이머리가 다운됐다고 알리는데 최대 2초가 소용된 후 선출을 시작한다.
11.4 롤백
- 프라이머리가 수행한 쓰기를 세컨더리가 복제하기 전에 프라이머리가 다운되면 다음에 선출되는 프라이머리에 해당 쓰기가 없을 의미한다.
예를 들어 네트워크 파티션이 각각 DC1, DC2 가 있다고 가정해보자.
이 두 파티션에서
DC1(주 연산#126)
- 세컨더리 A
- 세컨더리 B
DC2(주 연산 #125)
- 프라이머리 C
- 세컨더리 D
- 세컨더리 E
연산 #126의 불일치:
- DC2의 프라이머리 C는 네트워크 파티션이 발생하는 동안 연산 #125까지 수행
- 반면, DC1에서는 어떤 방식으로든 연산 #126을 수행했을 수 있으나, DC1에는 프라이머리가 없어 쓰기 작업은 불가능
서로 다른 서버들간에 동기화를 시작하지만 DC2에서는 연산 #126을 찾지 못한다. (이러면 롤백이 생긴다.)
DC1에서는 해당 도큐먼트 버전을 rollback 디렉토리의 .bson에 작성한다. 그리고 프라이머리에서 해당 컬렉션명.bson을 복제한다.
- MongoDB에서는 롤백을 수행할 때, 세컨더리 노드에서 프라이머리 노드로부터 동기화되었던 데이터 중 불일치가 발견된 데이터를 보존. 이 데이터는 rollback 디렉토리에 .bson 파일 형식으로 저장
- 롤백 후, 세컨더리 노드는 프라이머리 노드로부터 최신의 정확한 데이터 상태를 다시 복제 이 과정에서 프라이머리 노드의 데이터베이스 내 특정 컬렉션(예: collectionName.bson)의 내용을 세컨더리 노드에 전송하여 동기화
다만, 몽고DB 4.0 이전에는 롤백할 수 있는 양이 제한적이었다면 (얼만큼인지는 모르겠다.) 4.0 이후부터는 데이터 양이 제한이 없다.
- 300메가바이트 초과하거나 롤백에 시간이 30분이상 걸리면 실패할 수 있다.
'IT' 카테고리의 다른 글
트랜잭션 (0) | 2024.05.26 |
---|---|
resilience 4j 발표 내용 정리 (0) | 2024.04.21 |
몽고 디비 9장 (0) | 2024.04.01 |
Mongo 7 - 집계 (0) | 2024.03.11 |
6장 - 키-값 저장소 설계 (0) | 2024.02.12 |
댓글
이 글 공유하기
다른 글
-
트랜잭션
트랜잭션
2024.05.26 -
resilience 4j 발표 내용 정리
resilience 4j 발표 내용 정리
2024.04.21 -
몽고 디비 9장
몽고 디비 9장
2024.04.01 -
Mongo 7 - 집계
Mongo 7 - 집계
2024.03.11