(몽고DB 완벽 가이드) Chapter 10. 복제

이재문·2023년 11월 27일

10.1 복제 소개

  • 단일 mongod 서버를 실제 서비스 운영에 사용하면 매우 위험하다.
  • 복제로 한 대 또는 그 이상의 서버에 이상이 발생하더라도, 복제는 애플리케이션이 정상적으로 동작하게 하고 데이터를 안전하게 보존한다.
  • 몽고DB를 사용하면 복제 셋을 생성함으로써 복제를 설정할 수 있다.
  • 복제 셋은 클라이언트 요청을 처리하는 프라이머리 서버 한대, 프라이머리 데이터의 복사본을 갖는 세컨더리 서버 여러대로 이뤄진다.
  • 프라이머리 서버에 장애가 발생하면 세컨더리 서버는 자신들 중에서 새로운 프라이머리 서버를 선출 할 수 있다.
  • 복제를 사용하는 상태에서 서버가 다운되면, 복제 셋에 있는 다른 서버를 통해 데이터에 접근할 수 있다.

10.3 네트워크 고려 사항

  • 복제 셋의 모든 멤버는 같은 셋 내 다른 멤버와 연결할 수 있어야 한다.
  • 복제 셋의 각 멤버가 다른 멤버와 통신하려면 다른 멤버가 연결할 수 있는 IP주소에도 바인딩해야 한다.
  • —bind_ip를 지정하거나 config file에 있는 bind_ip를 사용해서 인스턴스를 다른 서버의 멤버와 함께 실행할 수 있다.
    $ mongod --bind_ip localhost,192.0.100.1 --replSet mdbDefGuide --dbpath ~/data/rs1 --port 27017 --iplogSize 200

10.4 보안 고려 사항

  • localhost 이외의 IP 주소에 바인딩하기 전 복제 셋을 구성할 때, 권한 제어를 활성화하고 인증 메커니즘을 지정해야 한다.
  • 데이터를 암호화하고, 복제 셋 멤버 간 통신 및 셋과 클라이언트 간 통신을 암호화하면 좋다.

10.5 복제 셋 설정

rsconf = {
	_id: "mdbDefGuide",
	members: [
		{_id: 0, host: "localhost:27017"},
		{_id: 1, host: "localhost:27018"},
		{_id: 2, host: "localhost:27019"},
	]
}

> re.initiate(rsconf) // 복제 셋 시작
{"ok": 1, "operationTime": Timestamp(,1)}
  • _id : 레플리카 셋 이름
  • host : 구성원들의 ip나 도메인
> rs.status()
  • 복제 셋의 상태를 볼 수 있다.
  • Privmary와 Secondary를 확인 할 수 있다.

rs 보조자 함수

  • rs는 복제 보조자 함수를 포함하는 전역 변수다.
  • 이 함수들은 거의 항상 DB명령을 감싸는 래퍼다. 예를 들어 다름 데이터베이스 명령은 rs.initiate(config)와 같다.

10.6 복제 관찰

  • 복제 셋이 다른 노드를 프라이머리로 선출했다면, 명령에 포트 번호를 지정해 프라이머리 노드에 연결한다.
    $ mongo --port 27018
  • 쓰기 시도를 했을 때 세컨더리 중 하나를 확인해 모든 도큐먼트의 사본이 있는지 확인 해 본다.
  • 셸을 종료하고 동일하게 포트번호를 연결해 작업할 수 있다.
  • db.isMaster()rs.status()보다 더 간결한 형태로 복제 셋의 상태를 보여준다.
  • isMaster 명령을 사용해 어느 멤버가 프라이머리가 됐는지 확인 할 수 있다.
  • 세컨더리로 복제된 컬렉션에 읽기를 시도할 때 에러가 날 수 있다.
    • 세컨더리는 프라이머리보다 뒤처지며 데이터가 최신이 아닐 수 있다.
    • 세컨더리는 애플리케이션으 stale 데이터를 읽지 않도록 기본적으로 읽기 요청을 거부한다.
    • 쿼리할 때 프라이머리가 아니다 라는 오류 발생
    • 플래그 설정으로 세컨더리 쿼리 가능
      secondaryConn.setSlaveOk()
    • 세컨더리에 직접 쓰기 또한 불가능
      > secondaryDB.coll.insert({"cound": 1001})
      >> writeError
      
      > secondaryDB.coll.count() // 변하지 X

      자동 장애 조치

      • 프라이머리가 중단되면 세컨더리 중 하나가 자동으로 프라이머리가 되는 기능
      • 프라이머리를 중단 시키고, secondaryDB.isMaster()를 실행해 세컨더리 서버가 프라이머리 서버가 된 것을 확인 가능

10.7 복제 셋 구성 변경

  • 복제 셋 구성은 멤버 추가, 삭제, 변경 언제든 가능
  • 뼈구이 or 텐동 or 만둣국 or 가빈이 or 맥도날두 or 스폰티니
    > rs.add("localhost:1234") // 새로운 멤버 추가
    
    > rs.remove("localhost:1234") // 멤버 제거
    • rs.config()에서 변경 사항 확인 가능
    • version 필드에서 변경 횟수 확인 가능
  • reconfig()로 여러 멤버를 추가하거나 제거할 수 있다.

10.8 복제 셋 설계 방법

  • 프라이머리를 선출하려면 멤버의 과반수 이상이 필요하고, 프라이머리는 과반수 이상이여야 자격을 유지할 수 있다.
  • 또한 쓰기는 과반수 이상이 복제되면 안전해진다.
  • 복제 셋의 과반수 의미 - 복제 셋 내 모든 멤버의 절반보다 많은 수치
  • 복제셋에 과반수가 다운되면 나머지 멤버들은 과반수가 되지 않으므로 프라이머리가 될 수 없고, 되어 있더라도 세컨더리가 된다. 프라이머리 0
  • 다운되었을 때, 과반수가 안된다고 프라이머리가 되지 않는 이유는 다운의 원인이 네트워크 인 경우 네트워크 파티션이 나눠진 경우 복제셋에서 두개의 프라이머리를 갖게 되고, 두개의 프라이머리에 쓰기가 되는 경우 데이터가 나뉘게 됨. 이러한 현상을 막기 위함
    • 1,2,3 의 데이터 센터와 4,5의 데이터 센터가 나눠진 상태 일 때, 1,2,3이 있는 데이터 센터에 프라이머리를 두는게 나은 설계이다.

10.8.1 어떻게 선출하는가?

  • 요청받은 멤버가 프라이머리에 도달 할 수 있는가?

  • 선출되고자 하는 멤버의 복제 데이터가 최신인가?

  • 대신 선출돼야 하는 우선순위가 더 높은 멤버는 없는가?

  • 복제 셋 멤버는 2초마다 ping을 보내는데 10초 이내로 pong을 반환하지 않으면, 다른 멤버가 불량 멤버를 접근 할 수 없음으로 표시

  • 우선순위가 가장 높은 세컨더리가 선출을 호출하도록 선출 알고리즘은 작동한다.

  • 우선순위가 더 높은 세컨더리가 있더라도, 더 낮은 인스턴스가 잠시 동안 프라이머리로 선출될 수 있다.

  • 프라이머리로 선출되려면 복제 데이터가 최신이어야 한다.

10.9 멤버 구성 옵션

10.9.1 우선 순위

  • 특정 멤버가 얼마나 프라이머리가 되기를 원하는지를 나타내는 지표 0~100 default: 1
  • priority: 0 이 되면 절대 프라이머리가 될 수 없다.
  • 우선 순위가 높은 멤버는 항상 프라이머리가 된다.
> rs.add({"host": "servier-4:12345", "priority": 2})
  • 위 명령어로 우선 순위를 2점으로 조정 가능
  • 현재 다른 멤버가 프라이머리였다면 프라이머리를 내려놓고 servier-4:12345 가 프라이머리가 된다.
  • 우선 순위를 높여도 데이터가 최신이 아니라면 프라이머리가 될 수 없다.

10.9.2 숨겨진 멤버

  • 숨겨진 멤버에 요청을 라우팅하지 않는다.
  • 복제 소스로 바람직하지 않다.
  • 보통 백업 서버로 숨긴다.
> config = rs.config()
> config.members[2].hidden = true
0
> config.members[2].priority = 0
0
> rs.reconfig(config)

> rs.isMaster()

{
	...
		"hosts" : [
				"server-1:12345",
				"server-2:12346"
				]
	...
}

rs.status()rs.config() 에서는 멤버를 보여줌

10.9.3 아비터 선출

  • 2-멤버 복제셋은 단점이 있다.
  • 소규모로 배포하면 데이터 복사본을 세 개 보관하기 힘들다. - 리소스 관리 힘듦
  • 프라이머리 선출에 참여하는 용도로 사용되는 특수 멤버를 지원 - 아비터
  • 아비터는 데이터 X, 클라 사용 X, 복제 셋에 과반수를 구성하는데만 사용
  • 일반적으로는 아비터가 없는 배포가 바람직하다.
> rs.addArb("server-5:12345") // 아비터를 복제 셋에 추가

> rs.add({"_id": 3, "host": "server-5:12345", "arbiterOnly": true})
  • 아비터는 복제 셋에 추가되면 아비터가 아닌것으로 구성하거나 아비터가 아닌것을 아비터로 구성하는건 안된다.

아비터는 하나만 사용하라

  • 노드의 개수가 홀수이면 하비터가 필요하지 않다.
  • 홀수에서 아비터를 추가하면 오히려 덜 안정적이다.
  • 선출 시간 또한 길어질 수 있다.
  • 동점 상황을 야기 할 수 있다.

아비터 사용 단점

  • 데이터 노드 > 아비터 - 선택지
  • 너무 작은 규모의 복제셋에서 아비터를 사용하면 관리가 힘들다.
  • 멤버가 둘인경우
    • 세컨더리 부족으로 관리하기 힘듦 (복제)
    • 프라이머리가 프라이머리이자 복제본, 다른 복제본을 가져오는 동안 부하 조절 개체 - 너무 많은 일을 함

10.9.4 인덱스 구축

  • 세컨더리는 프라이머리와 인덱스가 동일하지 않아도 된다.
  • "buildIndexes": false로 인덱스를 다르게 할 수 있음. - 영구 설정
  • 위 경우 일반멤버가 될 수 없음
  • 일반 멤버로 바꾸기
    • 복제셋 내 멤버 제거 → 데이터 삭제 → 복제셋 멤버 추가 → 새롭게 동기화
profile
이제부터 백엔드 개발자

0개의 댓글