10.1 복제 소개
- 단일 mongod 서버를 실제 서비스 운영에 사용하면 매우 위험하다.
- 복제로 한 대 또는 그 이상의 서버에 이상이 발생하더라도, 복제는 애플리케이션이 정상적으로 동작하게 하고 데이터를 안전하게 보존한다.
- 몽고DB를 사용하면 복제 셋을 생성함으로써 복제를 설정할 수 있다.
- 복제 셋은 클라이언트 요청을 처리하는 프라이머리 서버 한대, 프라이머리 데이터의 복사본을 갖는 세컨더리 서버 여러대로 이뤄진다.
- 프라이머리 서버에 장애가 발생하면 세컨더리 서버는 자신들 중에서 새로운 프라이머리 서버를 선출 할 수 있다.
- 복제를 사용하는 상태에서 서버가 다운되면, 복제 셋에 있는 다른 서버를 통해 데이터에 접근할 수 있다.
10.3 네트워크 고려 사항
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 명령을 사용해 어느 멤버가 프라이머리가 됐는지 확인 할 수 있다.
- 세컨더리로 복제된 컬렉션에 읽기를 시도할 때 에러가 날 수 있다.
10.7 복제 셋 구성 변경
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로 인덱스를 다르게 할 수 있음. - 영구 설정
- 위 경우 일반멤버가 될 수 없음
- 일반 멤버로 바꾸기
- 복제셋 내 멤버 제거 → 데이터 삭제 → 복제셋 멤버 추가 → 새롭게 동기화