이 글은 CentOS 7.x 이상, MongoDB v4.4.x 버전 사용을 전제로 합니다
시작하기 앞서
이 글의 목표는 원래 정상적으로 구동하던 기존 DB (이하 Primary Node)에 새로운 복제본 (이하 Secondary Node)을 추가하여 동기화를 최종적인 목적으로 합니다.
두 개의 복제본을 생성하여 복제본 상호간의 데이터와 Heartbeat를 공유해 안정적인 서비스를 지향하는 P-S-S 구성 또는 Heartbeat는 공유하지만 실질적으로는 데이터를 저장하지 않아 비교적 가볍게 운용이 가능한 Arbiter Node를 두번째 복제본 대신 사용하는 P-S-A 구성으로 진행할 수도 있습니다.
P-S-S 구성
P-S-A 구성
Secondary Node와 Arbiter Node는 Primary Node가 사용불가 상태인 경우 투표를 통해 새로운 Primary Node를 선출해 사용하게 됩니다. 이 때 Arbiter Node는 데이터를 저장하지 않는 Node이므로 실질적으로는 투표만 하는 Node입니다
투표는 과반수 이상이 참여해야하므로 가능한 한 홀수로 구성하는 것이 좋습니다
준비물
각각의 MongoDB 서버
각각의 노드는 주 버전이 같아야 합니다
네트워크 확인
라우터, 스위치 등에서 각각의 노드간 연결을 할 수 있도록 포트를 열어두어야 합니다 (예: MongoDB 기본 포트인 27017 포트)
주의사항
시스템 서비스를 이용한 MongoDB 서버 구동을 사용하지 않습니다
# MongoDB Deamon 종료 systemctl stop mongod # MongoDB 시스템 서비스 비활성화 systemctl disable mongod
가급적이면 도메인을 사용하는 것이 좋습니다
... # hosts 내용은 서버마다 다를 수 있습니다 #Primary Node가 속한 서버 127.0.0.1 mongo-primary mongo-secondary mongo-arbiter # 외부 서버 주소 10.0.0.1 external-secondary 10.0.0.2 external-arbiter
작업 시작
하나의 서버에서 P-S-A 구성을 사용하는 경우
필요한 파일과 디렉토리를 생성합니다
cd ~ # DB 디렉토리 생성 mkdir .db cd .db # 각 노드별 데이터가 저장될 디렉토리 생성 mkdir ./primary mkdir ./secondary mkdir ./arbiter # 로그가 저장될 디렉토리 생성 mkdir ./logs touch ./logs/primary.log touch ./logs/secondary.log touch ./logs/arbiter.log # 원본 config 파일을 DB 디렉토리로 복제 cp /etc/mongod.conf ./primary.conf cp /etc/mongod.conf ./secondary.conf cp /etc/mongod.conf ./arbiter.conf
각 Node에서 사용할 인증키를 생성합니다
openssl rand -base64 756 > ~/.db/.key chmod 400 ~/.db/.key
모든 .conf 파일을 수정합니다 (primary.conf, secondary.conf, arbiter.conf)
... systemLog: destination: file logAppend: true # Node에 맞게 수정 (예: /root/.db/logs/primary.log) path: /var/log/mongodb/mongod.log storage: # Node에 맞게 수정 (예:/root/.db/primary) dbPath: /var/lib/mongo journal: enabled: true # network interfaces net: # 포트 입력 (예: Primary = 27017, Secondary = 27018, Arbiter = 27019) port: 27017 # 접근 가능한 IP 입력 (상황에 따라 다르게 적용해야할 수 있습니다) bindIp: 0.0.0.0 security: # 인증 활성화 authorization: enabled # 키 파일로 인증 활성화 clusterAuthMode: keyFile # 키 파일 경로 입력 keyFile: /root/.db/.key #operationProfiling: replication: # 복제본 세트명 입력 (모든 Node의 replSetName은 같아야 합니다) replSetName: "rs0" ...
모든 MongoDB Node를 구동합니다
mongod --config ./primary.conf --fork mongod --config ./secondary.conf --fork mongod --config ./arbiter.conf --fork
MongoDB Shell를 이용해 Primary Node에 접근하여 로그인한 후 복제본 세트를 초기화합니다
# MongoDB Shell을 이용, Primary Node에 접근 mongo --port 27017
// 복제본 세트 설정값 cfg = { _id: "rs0", version: 1, members: [ { _id: 0, host: "mongo-primary:27017", priority: 2}, { _id: 1, host: "mongo-secondary:27018" }, { _id: 2, host: "mongo-arbiter:27019", arbiterOnly: true }, ] }
# replica set 초기화 rs.initiate(cfg)
도메인 네임 설정의 경우 /etc/hosts 파일을 열고 아래와 같이 추가합니다
... # for MongoDB replica set # 'mongo'와 같이 사용해도 무방하나 추후 확장 가능성을 고려해 작성 127.0.0.1 mongo-primary mongo-secondary mongo-arbiter
MongoDB Shell에서 모든 Node가 잘 연결되었는지 확인합니다
rs.status()
두개의 서버에서 P-S-A 구성을 사용하는 경우
필요한 파일과 디렉토리를 생성합니다
메인 서버 (Primary Node)
cd ~ # DB 디렉토리 생성 mkdir .db cd .db # 각 노드별 데이터가 저장될 디렉토리 생성 mkdir ./primary # 로그가 저장될 디렉토리 생성 mkdir ./logs touch ./logs/primary.log # 원본 config 파일을 DB 디렉토리로 복제 cp /etc/mongod.conf ./primary.conf
외부 서버 (Secondary Node, Arbiter Node)
cd ~ # DB 디렉토리 생성 mkdir .db cd .db # 각 노드별 데이터가 저장될 디렉토리 생성 mkdir ./secondary mkdir ./arbiter # 로그가 저장될 디렉토리 생성 mkdir ./logs touch ./logs/secondary.log touch ./logs/arbiter.log # 원본 config 파일을 DB 디렉토리로 복제 cp /etc/mongod.conf ./secondary.conf cp /etc/mongod.conf ./arbiter.conf
메인 서버에서 각 Node에서 사용할 인증키를 생성합니다
openssl rand -base64 756 > ~/.db/.key chmod 400 ~/.db/.key
rsync 등을 이용하여 외부 서버로 복사합니다
rsync -avh {계정명}@{메인 서버 주소}:{메인 서버내 인증 키 파일 경로} {로컬 경로}
모든 .conf 파일을 수정합니다 (primary.conf, secondary.conf, arbiter.conf)
... systemLog: destination: file logAppend: true # Node에 맞게 수정 (예: /root/.db/logs/primary.log) path: /var/log/mongodb/mongod.log storage: # Node에 맞게 수정 (예:/root/.db/primary) dbPath: /var/lib/mongo journal: enabled: true # network interfaces net: # 포트 입력 (예: Primary = 27017, Secondary = 27018, Arbiter = 27019)# port: 27017 # 접근 가능한 IP 입력 (상황에 따라 다르게 적용해야할 수 있습니다) bindIp: 0.0.0.0 security: # 인증 활성화 authorization: enabled # 키 파일로 인증 활성화 clusterAuthMode: keyFile # 키 파일 경로 입력 keyFile: /root/.db/.key #operationProfiling: replication: # 복제본 세트명 입력 (모든 Node의 replSetName은 같아야 합니다) replSetName: "rs0" ...
모든 MongoDB Node를 구동합니다
메인 서버
mongod --config ./primary.conf --fork
외부 서버
mongod --config ./secondary.conf --fork mongod --config ./arbiter.conf --fork
MongoDB Shell를 이용해 Primary Node에 접근하여 로그인한 후 복제본 세트를 초기화합니다
# MongoDB Shell을 이용, Primary Node에 접근 mongo --port 27017
// 복제본 세트 설정값 cfg = { _id: "rs0", version: 1, members: [ { _id: 0, host: "mongo-primary:27017", priority: 2}, { _id: 1, host: "mongo-secondary:27018" }, { _id: 2, host: "mongo-arbiter:27019", arbiterOnly: true }, ] }
# replica set 초기화 rs.initiate(cfg)
도메인 네임 설정의 경우 /etc/hosts 파일을 열고 아래와 같이 추가합니다
... # for MongoDB replica set 127.0.0.1 mongo-primary {외부 서버 주소} mongo-secondary mongo-arbiter
MongoDB Shell에서 모든 Node가 잘 연결되었는지 확인합니다
rs.status()
명령어
rs.add()
Secondary Node 추가
rs.conf()
현재 replica set의 설정값 확인
rs.status()
현재 replica set의 상태 확인
오류 해결
rs.initiate() 실행 중 발생하는 오류
{
"ok" : 0,
"errmsg" : "No host described in new configuration with {version: 1, term: 0} for replica set rs0 maps to this node",
"code" : 93,
"codeName" : "InvalidReplicaSetConfig"
}
hostname이 없는 경우
# /etc/hosts 파일을 수정한다 127.0.0.1 localhost localhost.localdomain ... [hostname 입력]