티스토리 뷰
728x90
반응형
13.1 독립 실행형 모드에서 멤버 시작
- 유지 보수 작업은 (쓰기와 관련) 세컨더리에서 수행 불가
- 애플리케이션 성능에 영향을 미치기 때문에 프라이머리에서 수행하면 안됨
- 복제 셋의 멤버가 아닌 독립 실행형 서버로 재시작해야함
- 이 서버에서 유지 보수를 수행하려면 replSet 옵션 없이 서버를 재시작
- 다른 서버에서 통신하지 않도록 다른 포트로 수신
- 서버의 데이터를 어떤 방식으로든 조작하기 위해 dppath는 그대로 유지
> db.serverCmdLineOpts()
{
"argv" : [ "mongod", "-f", "/var/lib/mongod.conf" ],
"parsed" : {
"replSet": "mySet",
"port": "27017",
"dbpath": "/var/lib/db"
},
"ok" : 1
}
> db.shutdownServer() //서버 종료
$ mongod --port 30000 --dbpath /var/lib/db //replSet 매개변수 없이 다른 포트에서 실행
13.2 복제 셋 구성
- 복제 셋 구성은 항상 local.system.replset 컬렉션의 도큐먼트에 보관
- 복제 셋의 모든 멤버에서 같음
- update 를 이용해 도큐먼트를 변경하지 말고, rs 보조자나 replSetReconfig 명령 사용
13.2.1 복제 셋 생성하기
- 멤버로 만들 mongod를 시작하고 그 중 하나에 rs.initiate() 를 사용해 구성 정보를 전달함으로써 복제 셋 생성
- 복제 셋의 한 멤버에서만 rs.initiate() 호출 가능
> var config = {
... "_id" : <setName>,
... "members" : [
... {"_id" : 0, "host" : <host1>},
... {"_id" : 1, "host" : <host2>},
... {"_id" : 2, "host" : <host3>}
... ]}
> rs.initiate(config)
13.2.2 복제 셋 멤버 교체하기
- 새로운 멤버를 추가할 때는 데이터 디렉터리에 아무것도 존재하지 않거나 (초기 동기화 수행)
- 다른 멤버 데이터의 복제본이 있어야함
> rs.add("spock:27017") //새로운 멤버 추가
> rs.add({"host" : "spock:27017", "priority" : 0, "hidden" : true}) //도큐먼트로 멤버 구성
> rs.remove("spock:27017") //"host" 필드를 이용해서 멤버 제거
- 멤버의 설정을 바꾸는데 제약 사항
- 멤버의 "_id"는 변경 불가
- 재구성 정보를 전달하려는 멤버(일반적으로 프라이머리)의 우선순위를 0으로 할 수 없음
- 아비터에서 아비터가 아닌 것으로 변경 불가, 반대도 불가
- 멤버의 "buildIndexes" 를 false에서 true로 변경 불가
- 멤버의 host 필드는 변경 가능
> var config = rs.config()
> config.members[0].host = "spock:27017"
spock:27017
> rs.reconfig(config)
13.2.3 큰 복제 셋 만들기
- 복제 셋에서 멤버는 50개, 투표 멤버는 7개로 제한
- 다른 멤버에 하트비트를 보내는 데 필요한 네트워크 트래픽량을 줄이고 선출에 걸리는 시간을 제한하기 위함
> rs.add({"_id" : 7, "host" : "server-7:27017", "votes" : 0}) //멤버들이 선출 과정에서 투표권을 행사하는 것을 방지
13.2.4 재구성 강제하기
- 복제 셋이 과반수를 영구적으로 잃으면, 프라이머리가 없는 상태에서 설정을 재구성할 필요
- 세컨더리에 재구성 명령을 보내 복제 셋 재구성을 강제
> rs.reconfig(config, {"force" : true})
- "force" 옵션은 유효하지 않은 구성 정보를 허용하지 않고, 세컨더리가 재구성 정보를 받아들이도록 허용
- 강제 재구성은 복제 셋 "version" 번호를 크게 높임.
재구성 정보가 네트워크 파티션 양쪽에 있을 때 버전 번호가 충돌하지 않도록 하기 위함 - 일부 멤버가 호스트명을 변경하면 예전 호스트명을 그대로 갖는 멤버를 강제 재구성
- 모든 멤버가 새로운 호스트명을 가지면 복제 셋의 각 멤버를 다운시키고,
새로운 멤버를 독립 실행형 모드로 시작한 뒤,
local.system.replset 도큐먼트를 수동으로 변경하고 멤버를 재시작
13.3 멤버 상태 조작
13.3.1 프라이머리에서 세컨더리로 변경하기
- stepDown 함수를 이용하면 프라이머리를 세컨더리로 강등
- 강등 기간동안 드란 프라이머리가 선출되지 않으면 세컨더리로 변했던 프라이머리는 재선출 시도
> rs.stepDown() //프라이머리를 60초 동안 세컨더리로 만든다
> rs.stepDown(600) // 10 minutes
13.3.2 선출 방지하기
- 프라이머리상에서 유지 보수 작업을 수행해야 하고, 그 사이에 자격이 있는 다른 멤버가 프라이머리가 되지 않게 하려면
- freeze 명령으로 세컨더리 상태에 머물게 함
- freeze 상태를 해제하려면 타임아웃을 0초로 지정
- 강등했던 프라이머리도 rs.freeze(0)으로 해제 가능
> rs.freeze(10000)
> rs.freeze(0)
13.4 복제 모니터링
13.4.1 상태 정보 가져오기
복제 셋의 모든 멤버의 정보를 얻는 명령어 replSetGetStatus
> rs.status()
13.4.2 복제 그래프 시각화
- rs.status() 결과의 syncingTo 필드 : 복제를 수행하는 호스트
- 복제 셋의 각 멤버에서 replSetGetStatus 명령으로 복제 그래프를 시각화
- server0 <- server1 <- server2 <- server4
> server1.adminCommand({replSetGetStatus: 1})['syncingTo']
server0:27017
> server2.adminCommand({replSetGetStatus: 1})['syncingTo']
server1:27017
> server3.adminCommand({replSetGetStatus: 1})['syncingTo']
server1:27017
> server4.adminCommand({replSetGetStatus: 1})['syncingTo']
server2:27017
- 핑 시간을 기준으로 동기화할 대상 결정
- 동기화할 멤버를 선택할 때, 멤버는 가장 가깝고 복제에서 자신보다 앞서 있는 멤버를 찾음 (복제 순환 발생 X)
- 다른 데이터센터의 프라이머리보다 같은 데이터 센터에 있는 멤버를 동기화
- 복제 사슬이 길어질수록 모든 멤버가 데이터의 복제본을 얻는데 오래 걸림
- replSetSyncFrom, rs.syncFrom() 으로 멤버의 복제 소스를 수정하여 문제 해결
> secondary.adminCommand({"replSetSyncFrom" : "server0:27017"})
13.4.3 복제 루프
- 모든 멤버가 다른 멤버로부터 복제를 수행하는 상태
- A <- B <- C <- A
- 모든 복제 루프는 프라이머리가 될 수 없으므로, 멤버들은 복제를 위한 새로운 명령을 받을 수 없고 뒤쳐짐
- replSetSyncFrom 명령으로 복제 소스를 수정할 때 복제 루프 발생
13.4.4 복제 사슬 비활성화
- 복제 사슬은 세컨더리가 또 다른 세컨더리와 동기화할 때 발생
- chainingAllowed 를 false로 모든 멤버는 프라이머리와 동기화
> var config = rs.config()
> config.settings = config.settings || {}
> config.settings.chainingAllowed = false
> rs.reconfig(config)
13.4.5 지연 계산하기
- 복제를 추적하는 지표로 세컨더리가 얼마나 프라이머리를 잘 따라잡는지 중요
- 지연은 세컨더리가 얼마나 뒤처지는지 프라이머리의 마지막 수행 연산과 세컨더리의 마지막 적용 연산의 타임스탬프 차이
- rs.printReplicationInfo()는 연산의 크기와 날짜 범위를 포함하는 프라이머리 oplog의 요약정보
> rs.printReplicationInfo();
configured oplog size: 10.48576MB
log length start to end: 3590 secs (1.00hrs)
oplog first event time: Tue Apr 10 2018 09:27:57 GMT-0400 (EDT)
oplog last event time: Tue Apr 10 2018 10:27:47 GMT-0400 (EDT)
now: Tue Apr 10 2018 10:27:47 GMT-0400 (EDT)
- rs.printSlaveReplicationInfo()는 각 멤버의 syncedTo 값과 마지막 oplog 항목이 세컨더리에 기록된 시간
> rs.printSlaveReplicationInfo();
source: m1.example.net:27017
syncedTo: Tue Apr 10 2018 10:27:47 GMT-0400 (EDT)
0 secs (0 hrs) behind the primary
source: m2.example.net:27017
syncedTo: Tue Apr 10 2018 10:27:43 GMT-0400 (EDT)
0 secs (0 hrs) behind the primary
source: m3.example.net:27017
syncedTo: Tue Apr 10 2018 10:27:39 GMT-0400 (EDT)
0 secs (0 hrs) behind the primary
13.4.6 Oplog 크기 변경
- 프라이머리의 oplog는 유지 보수 시간, 잘못된 부분을 고칠 수 있는 시간
- 일반적으로 1주 정도 데이터를 보유할 수 있는 oplog 가 바람직
- 일반적으로 oplog의 크기는 줄이면 안됨
1.복제 셋 멤버에 연결
2.oplog 의 현재 크기를 확인
> use local
> db.oplog.rs.stats(1024*1024).maxSize //메가바이트로 표시
3.복제 셋 멤버의 oplog 크기 변경
> db.adminCommand({replSetResizeOplog: 1, size: 16000}) //16기가
13.4.7 인덱스 구축하기
- 프라이머리에 인덱스 구축 전송하면, 세컨더리는 build index 연산을 복제할 때 인덱스를 구축
- 인덱스 구축은 멤버를 이용 불가능한 상태로 만들 수 있는 리소스 집약적 연산
- unique 인덱스 만들 때는 컬렉션에 모든 쓰기를 중지해야함. 복제 셋 멤버끼리 데이터 불일치 가능성
- 애플리케이션에 대한 영향을 최소화하려면 인덱스는 한 멤버씩 구축
- unique 인덱스 만들 때는 프라이머리에 먼저 구축
세컨더리 인덱스 구축
1. 세컨더리 종료
2. 종료한 세컨더리 독립 실행형 서버로 재시작
3. 재시작한 서버에 인덱스 구축
4. 서버를 복제 셋 멤버로 재시작
5. 복제 셋의 각 세컨더리에 1~4단계 반복
프라이머리 인덱스 구축
1. 프라이머리에 인덱스 구축. 트래픽이 적을 때 'off' 시간에 진행
읽기 선호도 수정하여 세컨더리로 부하를 보내도록 경로 변경
2. 프라이머리를 강등한 후 세컨더리 인덱스 구축 2~4단계 진행
인덱스 구축이 완료된 후 기존 프라이머리를 복제 셋에 재도입
13.4.8 한정된 예산에서 복제하기
- 성능 좋은 서버는 프라이머리로 쓰고,
- 상대적으로 값싼 서버는 재해 복구용 세컨더리 서버로 트래픽을 처리하지 않게 한다
- priority : 0 해당 서버가 절대 프라이머리가 되지 않도록 설정
- hidden : true 클라이언트가 해당 세컨더리에 읽기 요청을 절대 보내지 않도록 설정
- buildIndexes : false 처리해야하는 부하를 줄여줌
- votes : 0 해당 서버가 다운되더라도 기존 프라이머리가 유지되도록 해줌
728x90
반응형
'DB > MongoDB' 카테고리의 다른 글
[MongoDB] 샤딩 구성 (0) | 2023.12.10 |
---|---|
[MongoDB] 샤딩 (0) | 2023.08.30 |
[MongoDB] 애플리케이션에서 복제 셋 연결 (0) | 2023.08.01 |
[MongoDB] 복제 셋 구성 요소 (0) | 2023.07.27 |
[MongoDB] 복제 셋 설정 (0) | 2023.07.11 |
반응형
300x250