MongoDB 복제본 세트의 이해
MongoDB 샤드 클러스터를 효과적으로 다루기 위해서는 먼저 복제본 세트(Replica Set)의 개념을 명확히 이해하는 것이 필수적입니다. 복제본 세트는 여러 mongod 프로세스가 동일한 데이터 세트를 유지하며, 데이터 이중화와 높은 안정성을 제공하여 프로덕션 환경에서 데이터 무결성을 보장하는 핵심 기술입니다.
복제본 세트의 목적
데이터 복제는 시스템의 고장이나 단일 장애 지점(Single Point of Failure)으로 인한 데이터 손실 위험을 줄이는 데 목적이 있습니다. 여러 서버에 데이터 사본을 분산 저장함으로써, 주 서버에 문제가 발생하더라도 다른 서버가 신속하게 역할을 대체할 수 있습니다. 이는 시스템의 읽기 처리 능력 향상에도 기여하며, 부하를 분산하여 전체 시스템의 성능을 최적화합니다.
복제본 세트 개요
복제본 세트는 하나의 주(Primary) 노드와 여러 보조(Secondary) 노드로 구성됩니다. 주 노드는 모든 쓰기 작업을 처리하며, 보조 노드는 주 노드의 데이터를 복제하여 동기화 상태를 유지합니다. 모든 데이터 변경 사항은 주 노드의 oplog(operation log)에 기록됩니다. 주 노드에 장애가 발생하면, 보조 노드들 중에서 새로운 주 노드가 선출됩니다.
또한, 복제본 세트에는 데이터를 저장하지 않고 선출 과정에만 참여하는 아비터(Arbiter) 노드를 포함할 수 있습니다. 아비터는 경량 노드로, 주로 복제본 세트의 멤버 수가 짝수일 때 과반수 유지를 위해 사용됩니다.
복제본 세트 아키텍처
일반적인 복제본 세트는 최소 세 개의 멤버로 구성됩니다. 이는 모두 데이터를 저장하는 구성일 수도 있고, 아비터 노드를 포함할 수도 있습니다.
세 멤버 복제본 세트 (데이터 저장)
- 하나의 주 노드 (Primary)
- 두 개의 보조 노드 (Secondary)
주 노드 장애 시, 두 보조 노드 중 하나가 새로운 주 노드로 선출됩니다. 원래의 주 노드가 복구되면 보조 노드로 현재 복제본 세트에 다시 합류합니다.
세 멤버 복제본 세트 (아비터 포함)
- 하나의 주 노드 (Primary)
- 하나의 보조 노드 (Secondary)
- 하나의 아비터 노드 (Arbiter) - 데이터는 저장하지 않고 투표에만 참여
이 구성은 보조 노드가 하나뿐이므로 데이터 이중화 측면에서는 제한적입니다. 아비터 노드는 적은 리소스를 사용하지만, 장애 허용 범위가 줄어들 수 있습니다. 주 노드 장애 시 보조 노드가 주 노드로 승격됩니다.
주 노드 선출 (Primary Election)
복제본 세트는 rs.initiate() 명령으로 초기화된 후, 멤버들 간에 하트비트 메시지를 교환하고 주 노드 선출을 시작합니다. 과반수 투표를 얻은 노드가 주 노드가 되며, 나머지는 보조 노드가 됩니다.
과반수(Majority)의 정의: 투표 가능한 멤버 수가 N일 때, 과반수는 N/2 + 1입니다. 활성 멤버 수가 과반수 미만이면 주 노드를 선출할 수 없어 쓰기 작업이 불가능해지고 읽기 전용 상태가 됩니다.
| 투표 멤버 수 (N) | 과반수 | 허용 장애 수 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
| 7 | 4 | 3 |
일반적으로 복제본 세트 멤버 수를 홀수로 구성하는 것이 좋습니다. 위의 표에서 보듯이 3개 노드와 4개 노드 모두 1개의 노드 장애만 허용하므로, 서비스 가용성 측면에서는 3개 노드가 더 효율적입니다.
복제본 세트 멤버 유형
| 멤버 유형 | 설명 |
|---|---|
| Secondary | 정상적인 주 노드 선출에 참여하고, 주 노드로부터 최신 데이터를 복제하여 동기화합니다. 읽기 요청을 처리하여 복제본 세트의 읽기 처리량을 높일 수 있으며, 유연한 설정으로 다양한 시나리오에 활용됩니다. |
| Arbiter | 데이터를 저장하지 않고 주 노드 선출 투표에만 참여합니다. 복제본 세트 멤버 수가 짝수일 때 과반수 유지를 돕기 위해 사용되며, 매우 가볍습니다. |
| Priority 0 | 선출 우선순위가 0인 노드로, 주 노드로 선출되지 않습니다. 특정 데이터센터에 주 노드를 고정해야 할 경우 활용됩니다. |
| Vote 0 | MongoDB 3.0부터 복제본 세트의 투표 멤버 수는 최대 7개로 제한됩니다. 7개를 초과하는 멤버는 votes 속성을 0으로 설정하여 투표에 참여하지 않도록 합니다. |
| Hidden | 주 노드로 선출될 수 없으며(Priority 0), 클라이언트 드라이버로부터 읽기 요청을 받지 않습니다. 데이터 백업이나 오프라인 분석 작업에 활용하여 복제본 세트 서비스에 영향을 주지 않도록 합니다. |
| Delayed | Hidden 노드여야 하며, 주 노드보다 일정 시간(예: 1시간) 뒤처진 데이터를 유지합니다. 잘못된 데이터 쓰기나 실수로 인한 데이터 손실 시, 이전 시점으로 데이터를 복구하는 데 사용됩니다. |
Priority 0 노드: 특정 상황(예: 합리적인 시간 내에 새 멤버를 추가할 수 없을 때)에 대비한 백업 역할을 할 수 있습니다. 최신 데이터를 유지하여 비활성 멤버를 대체할 수 있습니다.
Hidden 노드: 클라이언트 드라이버가 읽기 요청을 보내지 않으므로, 보고서 생성이나 데이터 백업 등 애플리케이션에 영향을 주지 않는 용도로 사용됩니다. Delayed 노드도 Hidden 노드여야 합니다.
Delayed 노드: 주 노드보다 의도적으로 지연된 데이터셋을 가집니다. 애플리케이션 업그레이드 실패나 실수로 인한 테이블/DB 삭제 등 사용자 오류 발생 시, 과거 시점으로 데이터를 복구하는 데 유용합니다.
MongoDB 복제본 세트 설정
환경 준비
이 가이드에서는 CentOS 6.9 시스템과 MongoDB 3.2.8 버전을 사용합니다. 방화벽과 SELinux는 비활성화된 상태이며, 네트워크 인터페이스는 10.0.0.152를 사용합니다.
# 사용자 생성 및 MongoDB 설치 (root 사용자)
useradd -u800 mongo_user
echo "password123" | passwd --stdin mongo_user
mkdir -p /opt/mongodb/bin
cd /opt/mongodb
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.8.tgz
tar xf mongodb-linux-x86_64-3.2.8.tgz
cp mongodb-linux-x86_64-3.2.8/bin/* /opt/mongodb/bin
chown -R mongo_user:mongo_user /opt/mongodb
# mongo_user로 전환
su - mongo_user
필요한 디렉토리 생성
여러 MongoDB 인스턴스를 위한 디렉토리를 생성합니다. 이 예시에서는 27017, 27018, 27019 포트를 사용합니다.
for port in 27017 27018 27019
do
mkdir -p /opt/mongodb/$port/config
mkdir -p /opt/mongodb/$port/data
mkdir -p /opt/mongodb/$port/log
done
다중 인스턴스 환경 설정
첫 번째 인스턴스 (27017)의 설정 파일을 생성합니다.
cat >/opt/mongodb/27017/config/mongod.conf<<'EOF'
systemLog:
destination: file
path: /opt/mongodb/27017/log/mongo_replica.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /opt/mongodb/27017/data
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 0.5
directoryForIndexes: true
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
processManagement:
fork: true
net:
port: 27017
bindIp: 10.0.0.152
replication:
oplogSizeMB: 1024
replSetName: my_rs_cluster
EOF
생성된 설정 파일을 다른 인스턴스에 복사하고 포트 번호를 수정합니다.
for port in 27018 27019
do
cp /opt/mongodb/27017/config/mongod.conf /opt/mongodb/$port/config/
sed -i "s#27017#$port#g" /opt/mongodb/$port/config/mongod.conf
sed -i "s#mongo_replica.log#mongo_replica_${port}.log#g" /opt/mongodb/$port/config/mongod.conf
done
모든 MongoDB 인스턴스를 시작합니다.
for port in 27017 27018 27019
do
/opt/mongodb/bin/mongod -f /opt/mongodb/$port/config/mongod.conf
done
MongoDB 서비스 중지 방법:
for port in 27017 27018 27019
do
/opt/mongodb/bin/mongod --shutdown -f /opt/mongodb/$port/config/mongod.conf
done
복제본 세트 구성
MongoDB 셸에 접속하여 복제본 세트를 초기화합니다.
mongo --port 27017
// 복제본 세트 설정 정의
config = {
_id: 'my_rs_cluster',
members: [
{_id: 0, host: '10.0.0.152:27017'},
{_id: 1, host: '10.0.0.152:27018'},
{_id: 2, host: '10.0.0.152:27019'}
]
};
// 설정 초기화
rs.initiate(config);
주/보조 복제 테스트
주 노드에 데이터를 삽입하고, 보조 노드에서 해당 데이터가 복제되었는지 확인합니다.
my_rs_cluster:PRIMARY> db.inventory.insertMany([
{ item: "laptop", qty: 25, tags: ["electronics", "office"] },
{ item: "mouse", qty: 100, tags: ["electronics", "peripherals"] }
]);
my_rs_cluster:PRIMARY> db.inventory.find().pretty();
MongoDB 복제본 세트에서 보조 노드는 기본적으로 읽기 요청을 처리하지 않습니다. 보조 노드에서 읽기를 허용하려면 rs.slaveOk() (또는 db.getMongo().setReadPref('secondaryPreferred')) 명령을 사용해야 합니다.
주의: 보조 노드에서 데이터 변경 작업은 허용되지 않습니다.
my_rs_cluster:SECONDARY> rs.slaveOk(); // 보조 노드에서 읽기 허용
my_rs_cluster:SECONDARY> show collections;
my_rs_cluster:SECONDARY> db.inventory.find().pretty();
복제본 세트 관리 명령어
- 상태 확인:
rs.status();(전체 복제본 세트),rs.isMaster();(현재 노드의 역할) - 노드 추가/삭제:
rs.add("ip:port");(새 보조 노드),rs.addArb("ip:port");(새 아비터 노드),rs.remove("ip:port");(노드 삭제) - 지연 노드 설정 (일반적으로 Hidden 노드와 함께 설정):
cfg = rs.conf(); cfg.members[2].priority = 0; // 주 노드로 선출되지 않음 cfg.members[2].slaveDelay = 3600; // 1시간 지연 (초 단위) cfg.members[2].hidden = true; // Hidden 노드로 설정 rs.reconfig(cfg); - 복제본 세트 설정 조회:
rs.config(); - 역할 전환 (주의해서 사용):
rs.stepDown();(현재 주 노드를 보조로 강등),rs.freeze(300);(보조 노드의 주 노드 선출을 300초간 방지)
MongoDB 샤딩 기술
샤딩(Sharding)은 MongoDB에서 대규모 데이터 세트와 높은 처리량을 처리하기 위해 데이터를 여러 서버(또는 샤드)에 분산하는 기술입니다. 관계형 데이터베이스의 파티셔닝과 유사하지만, MongoDB는 데이터 분산을 거의 자동으로 처리합니다.
샤딩의 목적
단일 서버는 데이터 용량, CPU, 메모리, 디스크 I/O 측면에서 한계가 있습니다. 이러한 병목 현상을 해결하기 위해 수직 확장(더 강력한 단일 서버)과 수평 확장(데이터를 여러 서버에 분산)의 두 가지 방법이 있습니다. 샤딩은 바로 이 수평 확장을 구현하는 핵심 기술입니다.
샤딩을 통해 각 샤드가 처리해야 하는 요청 수가 줄어들고, 저장해야 하는 데이터 양도 감소합니다. 예를 들어, 1TB의 데이터셋이 4개의 샤드에 분산되면 각 샤드는 256GB만 저장하게 됩니다. 이는 시스템의 저장 용량과 처리량을 동시에 증가시킵니다.
샤딩의 이점
- 클러스터 추상화:
mongos라는 라우팅 프로세스가 클라이언트 요청을 적절한 샤드로 전달하고, 결과를 통합하여 반환합니다. 클라이언트는 복잡한 클러스터 구조를 인식할 필요가 없습니다. - 가용성 및 안정성: 샤딩과 복제본 세트를 결합하여, 각 샤드도 복제본 세트로 구성됩니다. 특정 서버에 문제가 발생해도 다른 복제본 멤버가 작업을 이어받아 서비스 중단을 최소화합니다.
- 쉬운 확장성: 시스템 용량이나 리소스가 부족해질 때, 필요에 따라 새로운 샤드를 쉽게 추가하여 클러스터를 확장할 수 있습니다.
샤드 클러스터 아키텍처
| 컴포넌트 | 설명 |
|---|---|
| Config Server | 클러스터의 메타데이터(모든 노드, 샤드 정보, 데이터 라우팅 정보)를 저장합니다. 일반적으로 세 개의 Config Server 노드로 복제본 세트를 구성합니다. |
| Mongos | 클라이언트 요청을 받아 적절한 샤드로 라우팅하고 결과를 통합하여 반환하는 쿼리 라우터입니다. 데이터 마이그레이션 및 자동 균형 조정에도 관여합니다. 일반적으로 여러 개의 mongos 인스턴스를 배포합니다. |
| Mongod (Shard) | 실제 애플리케이션 데이터를 저장하는 독립적인 복제본 세트입니다. 데이터는 "청크(Chunk)" 단위로 저장됩니다. 여러 샤드를 통해 데이터 분산이 이루어집니다. |
mongos는 자체적으로 데이터를 저장하지 않으며, 모든 샤드 클러스터의 메타데이터는 Config Server에 저장됩니다. mongos는 시작 시 Config Server로부터 메타데이터를 로드하여 클라이언트 요청을 올바른 샤드로 라우팅합니다.
클러스터 내 데이터 분산
청크(Chunk)란?
각 샤드 내부에서 MongoDB는 데이터를 청크 단위로 나눕니다. 각 청크는 특정 범위의 샤드 키 값을 포함하는 데이터 조각입니다.
- Splitting (분할): 청크 크기가 설정된 임계값(기본 64MB)을 초과하면, MongoDB 백그라운드 프로세스가 해당 청크를 더 작은 청크로 분할합니다.
- Balancing (균형 조정):
balancer라는 백그라운드 프로세스는 샤드 간의 청크 분포를 균등하게 유지합니다. 청크 수가 가장 많은 샤드에서 가장 적은 샤드로 청크를 이동시켜 부하를 분산합니다.
청크 크기(Chunk Size) 선택
청크 크기는 샤드 클러스터의 성능에 중요한 영향을 미칩니다. 적절한 청크 크기는 비즈니스 요구사항에 따라 달라집니다.
- 작은 청크 크기: 데이터 분할 및 마이그레이션이 빈번하여 데이터 분포가 더 균일해질 수 있습니다. 하지만 라우터(mongos)의 리소스 소모가 증가하고, 잦은 이동으로 I/O 부하가 발생할 수 있습니다.
- 큰 청크 크기: 데이터 분할이 적어 라우터의 부하를 줄일 수 있지만, 데이터 분포가 불균일해질 위험이 있습니다. 청크 이동 시 더 많은 I/O 리소스가 집중적으로 소모될 수 있습니다.
MongoDB의 기본 청크 크기는 64MB입니다. 특별한 요구사항이 없다면 이 값을 유지하는 것이 좋으며, 일반적으로 100-200MB 사이를 권장합니다. 청크 분할은 데이터 삽입 및 업데이트 시에만 발생하며, 읽기 작업 시에는 발생하지 않습니다.
데이터 구분: 샤드 키
샤딩은 컬렉션을 기반으로 이루어지며, 컬렉션 내의 데이터를 분할하기 위해 샤드 키(Shard Key)를 사용합니다. 샤드 키는 컬렉션 내의 문서에서 선택된 하나 이상의 필드로 구성되며, 이 필드의 값을 기준으로 데이터가 여러 샤드에 분산됩니다. 좋은 샤드 키는 데이터의 균일한 분산과 효율적인 쿼리 라우팅에 필수적입니다.
샤드 키의 중요 특성:
- 샤드 키는 불변입니다 (한번 설정하면 변경 불가).
- 샤드 키 필드에는 반드시 인덱스가 생성되어야 합니다 (
sh.shardCollection명령 시 자동 생성). - 샤드 키의 크기는 512바이트로 제한됩니다.
- 샤드 키는 쿼리 라우팅에 사용됩니다.
- 샤드 키가 설정된 컬렉션에는 샤드 키 필드가 없는 문서를 삽입할 수 없습니다 (null 값도 불가능).
범위 기반 샤딩 (Range-based Sharding)
MongoDB는 샤드 키의 값을 기준으로 데이터를 연속적인 범위로 나누어 청크를 생성합니다. 예를 들어, 숫자형 샤드 키의 경우, 특정 숫자 범위의 데이터가 하나의 청크에 할당될 수 있습니다. 이 방식은 유사한 샤드 키 값을 가진 문서들이 동일한 샤드에 저장될 가능성이 높습니다. 범위 쿼리에 효율적일 수 있습니다.
해시 기반 샤딩 (Hash-based Sharding)
해시 기반 샤딩은 샤드 키 필드의 해시 값을 계산하여 청크를 생성합니다. 이 방식은 샤드 키 값이 서로 비슷하더라도 해시 값은 완전히 다르게 분포될 수 있으므로, 데이터를 샤드 전체에 매우 균등하게 분산시킬 수 있습니다. 쓰기 작업의 확장성이 뛰어나지만, 범위 쿼리의 경우 모든 샤드에 쿼리를 전송해야 할 수 있어 비효율적일 수 있습니다.
샤드 키 선택 가이드라인
- 단조 증가하는 샤드 키: 데이터 삽입이 항상 마지막 샤드에 집중되어 쓰기 핫스팟을 유발할 수 있습니다. 하지만 데이터 파일 이동은 적을 수 있습니다.
- 무작위 샤드 키: 데이터 삽입이 여러 샤드에 고르게 분산되어 쓰기 부하를 균등하게 분산시킬 수 있습니다. 하지만 무작위 I/O가 많이 발생할 수 있습니다.
- 하이브리드 샤드 키: 큰 범위에서는 무작위적이고 작은 범위에서는 단조 증가하는 방식을 조합하여, 쓰기 분산과 쿼리 효율성을 동시에 고려할 수 있습니다.
샤드 키는 데이터의 분포와 쿼리 성능에 결정적인 영향을 미치므로 신중하게 선택해야 합니다. 대규모 청크 이동으로 인한 I/O 부하를 방지하기 위해 합리적인 청크 크기와 샤드 키 선택이 중요합니다.
샤드 클러스터 배포
이 섹션에서는 앞서 구성한 복제본 세트를 기반으로 샤드 클러스터를 구축하는 방법을 설명합니다.
환경 준비: 디렉토리 생성
샤드 클러스터의 다양한 구성 요소(샤드 복제본 세트, Config Server 복제본 세트, Mongos)를 위한 디렉토리를 생성합니다.
for port in 27021 27022 27023 27024 27025 27026 27027 27028 27029
do
mkdir -p /opt/mongodb/$port/config
mkdir -p /opt/mongodb/$port/data
mkdir -p /opt/mongodb/$port/log
done
샤드 복제본 세트 설정
두 개의 샤드 복제본 세트(sh1, sh2)를 구성합니다. 각 샤드는 3개의 멤버로 구성되며, 하나는 아비터입니다.
첫 번째 샤드(sh1)의 설정 파일 (27021) 생성:
cat > /opt/mongodb/27021/config/mongod.conf <<'EOF'
systemLog:
destination: file
path: /opt/mongodb/27021/log/shard_27021.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /opt/mongodb/27021/data
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 0.5
directoryForIndexes: true
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
net:
bindIp: 10.0.0.152
port: 27021
replication:
oplogSizeMB: 512
replSetName: sh1
sharding:
clusterRole: shardsvr
processManagement:
fork: true
EOF
설정 파일을 복사하고 포트 및 복제본 세트 이름을 수정합니다.
# sh1의 나머지 멤버 (27022, 27023) 설정
for port in 27022 27023
do
cp /opt/mongodb/27021/config/mongod.conf /opt/mongodb/$port/config/
sed -i "s#27021#$port#g" /opt/mongodb/$port/config/mongod.conf
sed -i "s#shard_27021.log#shard_${port}.log#g" /opt/mongodb/$port/config/mongod.conf
done
# sh2 멤버 (27024, 27025, 27026) 설정
for port in 27024 27025 27026
do
cp /opt/mongodb/27021/config/mongod.conf /opt/mongodb/$port/config/
sed -i "s#27021#$port#g" /opt/mongodb/$port/config/mongod.conf
sed -i "s#shard_27021.log#shard_${port}.log#g" /opt/mongodb/$port/config/mongod.conf
sed -i "s#sh1#sh2#g" /opt/mongodb/$port/config/mongod.conf
done
모든 샤드 인스턴스를 시작합니다.
for port in 27021 27022 27023 27024 27025 27026
do
/opt/mongodb/bin/mongod -f /opt/mongodb/$port/config/mongod.conf
done
샤드 복제본 세트 sh1 초기화:
mongo --host 10.0.0.152 --port 27021 admin
config_sh1 = {
_id: 'sh1',
members: [
{_id: 0, host: '10.0.0.152:27021'},
{_id: 1, host: '10.0.0.152:27022'},
{_id: 2, host: '10.0.0.152:27023', arbiterOnly: true}
]
};
rs.initiate(config_sh1);
샤드 복제본 세트 sh2 초기화:
mongo --host 10.0.0.152 --port 27024 admin
config_sh2 = {
_id: 'sh2',
members: [
{_id: 0, host: '10.0.0.152:27024'},
{_id: 1, host: '10.0.0.152:27025'},
{_id: 2, host: '10.0.0.152:27026', arbiterOnly: true}
]
};
rs.initiate(config_sh2);
Config Server 복제본 세트 설정
세 개의 Config Server 노드(27027, 27028, 27029)로 구성된 복제본 세트 cfg_rs를 설정합니다.
Config Server의 설정 파일 (27027) 생성:
cat > /opt/mongodb/27027/config/mongod.conf <<'EOF'
systemLog:
destination: file
path: /opt/mongodb/27027/log/config_27027.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /opt/mongodb/27027/data
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 0.25
directoryForIndexes: true
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
net:
bindIp: 10.0.0.152
port: 27027
replication:
oplogSizeMB: 128
replSetName: cfg_rs
sharding:
clusterRole: configsvr
processManagement:
fork: true
EOF
설정 파일을 복사하고 포트 정보를 수정합니다.
for port in 27028 27029
do
cp /opt/mongodb/27027/config/mongod.conf /opt/mongodb/$port/config/
sed -i "s#27027#$port#g" /opt/mongodb/$port/config/mongod.conf
sed -i "s#config_27027.log#config_${port}.log#g" /opt/mongodb/$port/config/mongod.conf
done
Config Server 인스턴스를 시작합니다.
for port in 27027 27028 27029
do
/opt/mongodb/bin/mongod -f /opt/mongodb/$port/config/mongod.conf
done
Config Server 복제본 세트 초기화:
mongo --host 10.0.0.152 --port 27027 admin
config_cfg = {
_id: 'cfg_rs',
members: [
{_id: 0, host: '10.0.0.152:27027'},
{_id: 1, host: '10.0.0.152:27028'},
{_id: 2, host: '10.0.0.152:27029'}
]
};
rs.initiate(config_cfg);
참고: MongoDB 3.4부터 Config Server는 반드시 복제본 세트여야 합니다.
Mongos 라우터 설정
mongos 라우터 (27017 포트)를 설정합니다. 이전에 사용했던 27017 포트를 재활용하거나 새로운 포트를 사용할 수 있습니다.
Mongos 설정 파일 (27017) 생성:
cat > /opt/mongodb/27017/config/mongos.conf <<'EOF'
systemLog:
destination: file
path: /opt/mongodb/27017/log/mongos_27017.log
logAppend: true
net:
bindIp: 10.0.0.152
port: 27017
sharding:
configDB: cfg_rs/10.0.0.152:27027,10.0.0.152:27028,10.0.0.152:27029
processManagement:
fork: true
EOF
mongos 인스턴스를 시작합니다.
/opt/mongodb/bin/mongos -f /opt/mongodb/27017/config/mongos.conf
mongos에 접속하여 샤드 노드를 클러스터에 추가합니다.
mongo 10.0.0.152:27017/admin
db.runCommand( { addshard : "sh1/10.0.0.152:27021,10.0.0.152:27022,10.0.0.152:27023", name: "shard_a" } );
db.runCommand( { addshard : "sh2/10.0.0.152:27024,10.0.0.152:27025,10.0.0.152:27026", name: "shard_b" } );
// 샤드 목록 확인
db.runCommand( { listshards : 1 } );
// 클러스터 전체 상태 확인
sh.status();
이로써 MongoDB 샤드 클러스터 구축이 완료되었습니다.
데이터베이스 샤딩 설정
샤딩을 적용할 데이터베이스(예: analytics_db)와 컬렉션(예: user_events)을 활성화합니다.
mongos> use admin;
mongos> db.runCommand( { enablesharding : "analytics_db" } );
mongos> use analytics_db;
mongos> db.user_events.ensureIndex( { eventId: 1 } ); // 범위 기반 샤딩을 위한 인덱스 생성
mongos> use admin;
mongos> db.runCommand( { shardcollection : "analytics_db.user_events", key : { eventId: 1 } } );
데이터를 삽입하여 샤딩이 잘 작동하는지 테스트합니다.
mongos> use analytics_db;
mongos> for(let i=0; i<50000; i++){
db.user_events.insertOne({
"eventId": i,
"userId": Math.floor(Math.random() * 10000),
"timestamp": new Date(),
"data": "event_details_" + i
});
}
mongos> db.user_events.stats();
더 많은 데이터를 삽입할수록 샤딩의 효과를 명확히 확인할 수 있습니다.
샤드 클러스터 운영
다양한 샤드 키 설정
- 범위 기반 샤드 키:
admin> sh.shardCollection("database.collection_name", { shard_key_field: 1 } ); - 해시 기반 샤드 키:
admin> sh.shardCollection("database.collection_name", { shard_key_field: "hashed" } );해시 기반 샤드 키를 사용하기 전에 해당 필드에 해시 인덱스를 생성해야 합니다.
admin> use database; admin> db.collection_name.ensureIndex( { field_name: "hashed" } );
샤드 클러스터 운영 명령어
- 샤드 클러스터 여부 확인:
admin> db.runCommand({ isdbgrid : 1}) - 모든 샤드 정보 목록:
admin> db.runCommand({ listshards : 1}) - 샤딩이 활성화된 데이터베이스 목록:
config> db.databases.find( { "partitioned": true } ) - 컬렉션의 샤드 키 정보 확인:
config> db.collections.find( { _id: "database_name.collection_name" } ) - 샤드 클러스터의 상세 상태 출력:
admin> sh.status()또는admin> db.printShardingStatus() - 샤드 노드 제거 (점진적으로 데이터를 비우며 제거):
mongos> db.runCommand( { removeShard: "shard_name" } )
Balancer (균형 조정자) 작업
Balancer는 샤드 클러스터의 청크를 샤드 간에 균등하게 분산하는 프로세스입니다.
Balancer 상태 확인: mongos> sh.getBalancerState()
데이터 마이그레이션 진행 여부 확인: mongos> sh.isBalancerRunning()
Balancer 활동 시간대 설정
Balancer가 특정 시간대에만 작동하도록 설정할 수 있습니다. 이는 피크 시간 동안 I/O 부하를 줄이는 데 유용합니다.
mongos> use config;
mongos> db.settings.update(
{ _id: "balancer" },
{ $set: { activeWindow : { start : "01:00", stop : "05:00" } } }, // 새벽 1시부터 5시까지
{ upsert: true }
);
주의: 설정된 시간 내에 모든 데이터 마이그레이션이 완료될 수 있도록 충분한 시간을 할당해야 합니다.
Balancer 활동 시간대 삭제:
mongos> use config;
mongos> db.settings.update( { _id : "balancer" }, { $unset : { activeWindow : true } } );
Balancer 일시 중지 및 재활성화
Balancer를 일시적으로 중지할 수 있습니다.
mongos> sh.stopBalancer();
// Balancer가 완전히 중지될 때까지 기다림
mongos> use config;
mongos> while( sh.isBalancerRunning() ) {
print("Balancer is still running. Waiting...");
sleep(1000);
}
중지된 Balancer를 다시 활성화합니다.
mongos> sh.setBalancerState(true);
특정 컬렉션의 Balancer 제어
특정 컬렉션에 대한 Balancer 작동을 비활성화하거나 활성화할 수 있습니다.
- 비활성화:
sh.disableBalancing("database.collection_name") - 활성화:
sh.enableBalancing("database.collection_name") - 상태 확인:
db.getSiblingDB("config").collections.findOne({_id : "database.collection_name"}).noBalance;
성능 문제 해결
Balancer가 자동으로 청크를 이동할 때 데이터베이스 응답이 느려질 수 있습니다. 이러한 문제를 해결하려면 자동 균형 조정을 비활성화하거나, 작업량이 적은 시간대로 Balancer 활동 시간대를 조정할 수 있습니다.
# 자동 균형 조정 비활성화
mongos> use config;
mongos> db.settings.update( { _id: "balancer" }, { $set : { stopped: true } } , true );
# 자동 균형 조정 시간대 설정 (예: 밤 10시부터 아침 8시까지)
mongos> use config;
mongos> db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "22:00", stop : "8:00" } } }, true );