개발과 기록의 조화

[MongoDB] 복제 (Replica Set) 본문

Database/MongoDB

[MongoDB] 복제 (Replica Set)

dlaudtjr03 2020. 2. 12. 16:43
해당 게시물은 학습 및 기록 목적으로 작성되었습니다. 사실과 다른 내용이 있을 수 있으며, 오류가 있거나 궁금한 점은 댓글이나 dlaudtjr07@gmail.com 으로 메일 주시면 감사하겠습니다.

 


Replica Set Member

MongoDB 에서의 Replica Set은 '중복성' , '가용성'을 제공하는 프로세스 그룹입니다. Primary, Secondary로 나뉩니다.

  • Primary : 모든 쓰기 작업을 할당받습니다.
  • Secondary : Primary에서 작업을 복제해 똑같은 데이터 셋을 유지합니다. 특수한 용도에 따른 추가 구성이 있을 수도 있습니다.

Client는 Secondary에 직접적으로 Write를 수행할 수 없습니다만, Read 작업을 통한 데이터 읽기는 가능합니다.

 

 

Primary에 장애가 발생하면, MongoDB는 Secondary 중 하나를 Primary로 권한을 위임해 계속해서 서버를 유지합니다.

Secondary 권한 위임 중에는 오로지 Read, 검색 기능만 가능하고 그 외의 CUD 작업은 컨트롤할 수 없습니다.

Secondary는 3.0.0 버전 이후로 최대 50개까지 보유 가능하며, 그 중 Primary 장애 발생 시 위임받을 Secondary는 7개로 제한합니다.

 

Arbiter

유사시 Primary의 작업 권한을 Secondary에게 위임할 때는 Arbiter라는 서버에 의해 컨트롤됩니다.

직접적인 데이터 저장 기능을 가지지는 않습니다. 하지만 유사시 Primary 서버를 버리고 여러 Secondary 서버 중 하나를 마스터 서버로 승격시켜야 하는데, 해당 투표권을 가지고 있는 서버가 바로 'arbiter' 서버입니다. DB 서버에 장애 발생시 외에는 별다른 작업이 없는 서버입니다.

 

Oplog

데이터 동기화가 목적인 Oplog는 Primary에 요청되는 작업들이 로그로 기록되는 파일입니다.  이 oplog 파일을 복사해 Secondary에 적용합니다. 모든 복제본 세트 멤버는 local.oplog.rs 콜렉션에 oplog 사본이 포함되어 현재 Primary Set의 데이터와 똑같이 유지할 수 있습니다.

(데이터 동기화가 목적이므로 Write에 관련된 연산만 기록됩니다)

 

ts(TimeStamp)

OpLog 저장 순서를 결정하는 기준이 되는 필드입니다. 2개 값으로 구성되어져 있는데, 첫 번째는 초 단위의 Unix Epoch, 두 번째 값은 동일 시간에 발생된 이벤트의 논리 시간을 표현합니다. 

t(Primary Term)

레플리카 셋의 프라이머리를 선출하는 투표가 실행될 때마다 증가하는 값입니다. 

h(Hash)
데이터 변경 작업에 OpLog의 해시 값을 이용해 식별자를 할당해 저장합니다.

v(Version)

OpLog 도큐먼트 버전입니다.

op(Operation Type)

프라이머리 멤버에서 실행된 Operation(CRUD) 종류를 저장합니다.

i(Insert) , d(Delete), u(Update), c(Command), n(No Operation) 등이 있습니다. n은 정보성 메세지를 의미합니다.

ns(NameSpace)

데이터가 변경된 대상 컬렉션의 네임스페이스(DB이름 + 컬렉션이름)가 저장됩니다.

에를 들어 op 필드가 c인 경우에 'db_name$cmd' 가 저장되며, n인 경우에는 빈 값으로 저장됩니다.

o(Operation)

실제 컬렉션의 도큐먼트가 변경된 값을 저장하는 필드입니다.

o2(Opearion 2)

업데이트될 대상 도큐먼트의 프라이머리 키인 "_id" 필드 정보를 저장합니다.

 

Replica Set 아키텍쳐

MogoDB에서 기본으로 지정한 프로덕션 시스템의 표준 Replica Set은 3개의 복제 세트로 이루어져 있습니다.

사용자가 설계할 아키텍쳐에 따라 다르지만, 최대 Secondary 멤버 수 50개 , 최대 위임 투표 가능 수 7개인것을 고려해 설계해야 합니다. 추가적으로 로드밸런싱 여부, 배포 사이즈, 사용 용량, 지리적 요건(AZ), 배포 방식 등 여러가지를 고려해 최적의 성능을 낼 수 있는 아키텍쳐를 설계하도록 권장합니다.

 

장애 여부 판단

Replica Set의 장애는 크게 Master 서버의 장애, Slave 서버의 장애로 구분됩니다. 해당 장애 여부에 따라 MongoDB에서 작업하는 프로세스가 다릅니다.

  • Secondary(Slave) 서버 장애는 Primary(Master) 서버 장애에 영향을 끼치지 습니다. 즉 마스터 권한 위임 투표 또한 수행하지 않습니다.
  • Primary 서버는 투표권이 존재하는 Secondary의 득표율을 절반 이상 넘기지 못하면 Master 지위를 일정 시간 후에 반납하고, 새로운 Master를 선출합니다.
  • Master 서버를 위한 투표는 최소 2개 이상의 Slave 서버가 필요합니다. 하나의 Slave 서버는 마스터로 선출되지 않습니다. 

위 리스트와 같은 조건으로 MongoDB는 상황에 맞는 프로세스를 처리합니다.

 

프라이머리 Term

프라이머리 텀은 논리적 시간 값으로써 각 레플리카 셋의 멤버들이 프라이머리 투표를 시도할 때마다 1씩 증가하는 식별자 입니다.

 

탄생 이유

이전 버전(3.2) 까지는 프라이머리 투표는 30초에 한 번만 실행 가능하도록 설계되었습니다. 즉 투표가 한 번 실패하면 해당 레플리카 셋은 30초동안은 프라이머리가 없는 상태로 대기 , 그 동안에 CUD 처리가 불가능했던 것입니다.

투표 방식도 복잡했습니다. 위와 같은 상황을 줄이기 위해 몽고디비는 2단계 투표 방식을 채택했는데, 사전 투표, 본 투표 두 가지의 방식으로 프라이머리 선출을 시도했습니다. 프라이머리가 되려고 하는 Secondary는 다른 Secondary 멤버들에게 자기 자신이 프라이머리가 되려고 하면 반대하지 않을 것인가에 대한 여부를 판단하고 , 반대하지 않을 시 본 투표를 시작하는 방식으로 이루어져 진행했습니다. 이와 같은 복잡한 프라이머리 선출 과정을 해결하기 위해 프라이머리 Term 이라는 방식이 도입되었습니다. 

프라이머리 Term 식별자를 기준으로 Secondary 자신이 투표를 했는지 , 투표에 참여해야 하는지에 대한 여부를 결정할 수 있는 것입니다. 또 다른 기능으로는, 현재 프라이머리 멤버가 OpLog에 현재 텀 식별자를 같이 기록합니다. 이는 프라이머리 상태였을 때의 로그인지 식별할 수 있게 해주는 기능이 있습니다.

 

프라이머리 Step Down

보통은 프라이머리에 문제가 생겼을 때 (네트워크, 서버 문제) 레플리카 셋은 새로운 프라이머리를 선출하기 위한 투표를 실시할 것입니다. 하지만 관리자가 현재 프라이머리를 의도적으로 세컨드리로 내리는 작업 또한 가능합니다. 이를 프라이머리 Step Down이라고 부릅니다.  

 

MongoDB Replication에서의 롤백

몽고DB Replication에서 사용되는 롤백의 의미는 우리가 알고 있던 RDMS 트랜잭션에서의 롤백하고는 전혀 다른 의미로 사용됩니다. MongoDB에서의 롤백은 레플리카 셋의 각 멤버끼리 데이터 동기화 과정에서 이미 저장된 데이터를 다시 삭제하는 과정을 의미합니다.

 

하나의 예시를 들어 보겠습니다. mongo2와 mongo3 세컨드리 레플리카 멤버는 프라이머리 멤버의 OpLog 데이터 각각 5번, 4,5번을 동기화시키지 못했다고 가정해 봅시다.  

 

중간에 프라이머리 멤버가 연결 불가 상태가 되었습니다. 그렇다면 투표를 통해 새 프라이머리를 선출할 것이고, 이에 mongo2 멤버가 프라이머리로 선출이 되었습니다. 하지만 아직 5번의 데이터는 동기화되지 않은 상태입니다.

이에 새 프라이머리 멤버 mongo2는 새로운 데이터 변경 로그를 기록할 것입니다.

mongo1 멤버의 장애가 복구되면 다시 레플리카 셋의 멤버로 활동하게 될 것입니다. 하지만 그 전에 새로운 프라이머리 멤버의 OpLog와 자신의 OpLog 데이터를 동기화해야 합니다. 시간 역순으로 두 OpLog 데이터를 대조하면서 어느 시점에 자기 자신과 현재 프라이머리 OpLog에 공통으로 있는 데이터를 찾으면, 해당 로그를 기점 이후의 모든 OpLog를 삭제합니다.

 

이는 단순히 OpLog의 기록만 삭제하는 것이 아닌, OpLog의 내용을 기반으로 실제 컬렉션 도큐먼트를 찾아 삭제, 변경 전 데이터로 되돌리는 작업을 수행합니다. 또한 삭제 전, 롤백할 해당 도큐먼트의 _id를 기준으로 다른 레플리카 셋 멤버가 가진 최신 버전의 도큐먼트를 가져와서 롤백 작업을 완료하게 됩니다. 그리고 롤백 과정에서 삭제, 변경된 도큐먼트들은 'rollback' 디렉토리에 기록합니다. 

 

위와 같은 작업을 거치고 나서 새로운 프라이머리 mongo2를 기반으로 데이터 동기화 작업을 거치게 됩니다. 예제는 아래와 같이 동기화가 완료된 상태를 보여주게 됩니다.

MongoDB 롤백 용량을 넘기고 프라이머리 장애 발생 시 롤백 에러가 발생합니다. 이와 같은 경우에는 수동으로 동기화 작업을 완료해야 합니다.

 

멤버 우선순위(Priority)

 

Priority는 레플리카 셋 멤버가 프라이머리 노드가 될 수 있는 우선순위를 의미합니다. (0~1000까지의 수치이며, 수치가 높을 수록 우선순위가 가장 높습니다) Priority가 0인 경우에는 프라이머리 노드가 될 수 없습니다.

 

아래와 같이 모든 레플리카 멤버의 우선순위가 1인 레플리카 셋이 있다고 가정합시다. 

 

mongo2 멤버의 우선순위를 2로 변경하면, mongo1은 자동으로 프라이머리 권한을 해제하고 새로운 프라이머리를 찾을 것입니다. 그 기준값이 priority입니다. 

 

또 다른 예로 mongo1의 우선순위가 2라고 가정하겠습니다. 위와 같은 경우에는, mongo1 멤버가 일시적으로 사용이 불가능할 때 다른 세컨드리 멤버에서 프라이머리 역할을 할 멤버를 선출할 것입니다. 다른 세컨드리가 프라이머리로 임명된 후에 mongo1 멤버가 복구가 완료된다면, 그 시점 프라이머리로 임명되었던 멤버는 자동적으로 프라이머리 권한을 해제하게 되고, 다시 mongo1 멤버가 프라이머리 권한을 얻게 되는 것입니다. 

 

레플리카 셋에서 특정 서버가 반드시 프라이머리가 되어야 할 필요성이 있다면 priority 설정은 필수적입니다. 하지만 특별하게 그러지 않아도 되는 경우에는 좋은 방법이 아닙니다. 프라이머리 선출 과정 동안에는 서비스 쿼리가 수행이 불가능하기 때문입니다. 


해당 글은 코드프레소 DevOps Roasting 코스를 수강하면서 작성한 글입니다.

 

Comments