시냅스

MongoDB Sharded Cluster, Docker 로 빠르게 올려보기 본문

데이터베이스/MongoDB

MongoDB Sharded Cluster, Docker 로 빠르게 올려보기

ted k 2024. 8. 14. 22:20
이 프로젝트는 Sharded Mongo Cluster 를 Docker 로 올려보며 간단하게 알아봅니다.
production level에서는 전혀 권장되지 않는 설정입니다.

MongoDB Sharded Cluster

 

Sharding 데이터베이스의 수평 확장을 의미합니다.

MongoDB에서는 Collection Shard Key 기준으로 나누어 여러 Shard 분산 저장합니다.

이를 통해 데이터의 관리와 접근성을 향상시킬 있습니다.

Shard 독립적으로 Read Write 작업을 수행하며 이로 인한 성능 향상을 기대할 수 있습니다.

 

전통적인 RDB MariaDB, MySQL 에서도 Sharding Cluster 를 구성할 수 있습니다. (Galera Cluster, MySQL Cluster)

특히 Galera Cluster 는 Multi Master 의 구조로 PK 를 기준으로 인증이라는 절차를 거쳐 데이터를 저장하는데요.

이때 Deadlock 의 발생 확률이 굉장히 높습니다. (자세한 내용은 제 블로그 Galera Cluster 와 관련된 글을 참고 부탁드립니다.)

따라서 Node 가 늘어나면 늘어날 수록 위와 같은 문제가 발생할 확률이 높아지기 때문에 Scale Out 을 주저하게 됩니다.

또 각 Shard 에 대한 처리를 Application Level 에서 정의할 필요가 있습니다.(Shard Key... Read Write Split...)

혹은 Proxy SQL 과 같은 추가 Application 을 구성해야 할 필요가 있습니다.

이는 관리 포인트가 늘어남으로 피로함을 느끼게 됩니다.

 

이에 반해 MongoDB Sharded Cluster 는 사용하기 굉장히 간편합니다.

개발자는 URI 정보만 기입하여 Router(Mongos) 로 쿼리를 넘겨주면

Mongos가 알아서 sharding 과 관련된 처리를 하기 때문입니다.

 

아래에서 실제로 구현해보며 알아보도록 하겠습니다.

 

 

MongoDB Sharded Cluster 구성

 

 

 

https://github.com/taesukang-dev/docker-mongo-sharded-cluster

 

GitHub - taesukang-dev/docker-mongo-sharded-cluster: Practicing with a MongoDB sharded cluster using Docker

Practicing with a MongoDB sharded cluster using Docker - taesukang-dev/docker-mongo-sharded-cluster

github.com

 

위 구성도를 토대로 설정해보도록 하겠습니다.

세로 1, 2, 3은 물리적으로 다른 위치임을 의미하며 Shard A, Shard B 는 논리적으로 다른 위치임을 의미합니다.

깃허브에 Configuration file, docker-compose 를 업로드 하였으니 참고 부탁드립니다.

 

  • Replica Set (Shard A, Shard B)
    • primary (27018)
    • Secondary (17017)
    • Arbiter (27021, 27022)

Shard 는 2개로 Shard Key 에 따라 각각 A/B 로 나누어져 적재됩니다.

이후 쿼리를 수행할 때에는 각 Shard 에서 병렬적으로 쿼리가 수행되므로 성능을 향상시킬 수 있습니다.

 

Primary 노드는 Write 작업을 수행하는 Master 노드입니다.

Secondary 노드는 Read 작업을 수행하는 Slave 노드입니다.

Arbiter 는 정족수를 맞추기 위한 노드로 실제 데이터를 저장하지 않습니다. 다만 실제로는 Secondary 로 설정하는 것이 좋습니다.

 

MongoDB 는 Write Concern 이라는 옵션을 사용하여 Transaction 을 제어합니다.

Write Concern 에 지정한 Node 가 write 연산을 마쳤다고 Primary 에 응답하면 Transaction 이 commit 되는 구조입니다.

이때 Write Concern 을 Majority 로 설정할 경우 3대 중에 Arbiter 가 아닌 Primary, Secondary 만 투표에 참여할 수 있는데

2대 중 1대인 primary 만 투표한다면 현재 split brain 상황인지 아닌지에 대한 판단을 내리기 어려울 수 있습니다.

따라서 Arbiter 는 Secondary Node 일 필요가 있고 자세한 내용은 최하단 참고에 링크한 MongoDB 총 정리 글을 확인해주세요.

 

또한 Primary, Secondary, Arbiter 는 물리적으로 다른 위치에 배치(1,2,3)하여 고가용성과 내결함성을 만족해야 합니다.

 

  • Configuration Server (27019)

Sharded Cluster 는 Metadata 를 담당하는 Configuration Server 가 필요합니다.

이때에도 Replica Set 과 마찬가지로 홀수를 유지하여 3대를 띄울 필요가 있습니다.

Config Server 는 Mongos 에서 `config` Database 로 확인이 가능하고

Cluster 의 Metadata (chunks, collections, shards...) 등을 관리합니다.

이를 통해 client 는 mongos 로 접속하여 CRUD 쿼리를 수행하고 Mongos 는 각 shard 에 분배합니다.

 

  • Mongos (27017)

Mongos는 클라이언트의 요청을 받아 Shard 로 라우팅하는 역할을 하게 됩니다.

마찬가지로 HA 를 위해 최소 2대가 필요합니다.

 

 

설치

깃허브 폴더 1, 2, 3 은 각각 다른 물리적 위치여야 합니다.

아래에서 명시할 host 부분 {1}, {2}, {3} 은 실제 각 물리 machine 이 사용하는 IP 여야 합니다.

 

우선 1, 2, 3 directory를 각각 원하는 machine 에 위치시킨 후 Base Directory(docker-compose 와 같은 위치) 에서

Replication 인증에 사용할 key 를 생성합니다.

$ openssl rand -base64 756 > mongodb.key
$ chmod 400 mongodb.key
$ chown 999:999 mongodb.key

 

 

 

위와 같이 권한을 조정하여 docker mongodb 가 사용할 수 있게 합니다.

이후 docker-compose 를 각각 machine 에서 실행합니다.

 

 

$ pwd
> .../1

$ docker-compose up -d

 

이때 만약 data 가 생기지 않아 container 가 뜰 수 없다는 에러를 반환한다면

{NODE}/data, log directory 를 chmod(777 또는 666) 로 조정합니다.

 

 

...
#sharding:
#  clusterRole: shardsvr
#security:
#  authorization: enabled

 

간혹 mongodb 가 initialize 되기 전에 sharding cluster role 을 정의하면 뜨지 않는 경우가 있습니다.

그 경우 각 node 의 mongod.conf 에 위 내용들을 주석 처리 합니다.

연습을 위한 것이므로 security 항목도 주석처리하여도 무방합니다.

이후 Container 를 올려 초기화 시키고 내린 후  주석을 해제하고 Conatiner 를 재실행합니다.

 

 

# {NODE}/mongos/mongos.conf
sharding:
	# mongos 가 configuration server 에 대한 정보를 알 수 있도록 합니다.
    configDB: "cfgrepl/{1}:27019,{2}:27019,{3}:27019" 

# {NODE}/rs_{REPLICA_SET_NUMBER}_mongo, arbiter/mongod.conf
replication:
  replSetName: "rs0" # replica set 이름을 정의합니다.
sharding:
  clusterRole: shardsvr # shard server 임을 정의합니다.

# {NODE}/mongo_config/mongod.conf
replication:
  replSetName: "cfgrepl" # replica set 이름을 정의합니다.
sharding:
  clusterRole: configsvr # config server 임을 정의합니다.​

 

위는 각 node 들의 mongod.conf 내용입니다.

추가 설정에 대한 확인은 github 를 참고 부탁드립니다.

 

 

# {1} 에서 수행, Replication Set 0번 설정
$ docker exec -it mongo-rs0-primary mongosh -u root -p 1234 --port 27018
mongo > rs.initiate({
	 _id: "rs0",
	 members: [
	   {_id: 0, host: "{1}:27018", priority: 2}, # priority 는 master 가 될 가중치, 높을 수록 우선순위 높음
	   {_id: 1, host: "{2}:17018", priority: 1},
	   # 위에서 상술했듯 Arbiter 는 데이터를 갖고 있지 않음, 다만 Secondary Node 로 띄우는 것을 권장
	   # 만약 Secondary 로 띄울 때에는
	   # {_id: 2, host: "{3}:27021"} 로 설정 가능 
	   {_id: 2, host: "{3}:27021", arbiterOnly:true, priority: 0}  # node 를 arbiter 로 실행한다.
	 ]
});

# replication 확인
mongo > rs.status()

 

1번 위치의 machine-primary 에서 수행합니다. "rs0" Replica Set 을 정의합니다.

앞서 언급했듯 {1}, {2}, {3}은 각 machine 의 ip 를 작성합니다.

또한 {3} Node는 arbiterOnly:true 옵션을 사용하여 데이터는 갖지 않고 정족수에만 참여함을 정의합니다.

 

 

# {2}에서 수행, Replication Set 1번 설정
$ docker exec -it mongo-rs1-primary mongosh -u root -p 1234 --port 27018
mongo > rs.initiate({
	 _id: "rs1",
	 members: [
	   {_id: 0, host: "{2}:27018", priority: 2}, # priority 는 master 가 될 가중치, 높을 수록 우선순위 높음
	   {_id: 1, host: "{1}:17018", priority: 1},
	   # 위에서 상술했듯 Arbiter 는 데이터를 갖고 있지 않음, 다만 Secondary Node 로 띄우는 것을 권장
	   # 만약 Secondary 로 띄울 때에는
	   # {_id: 2, host: "{3}:27022"} 로 설정 가능 
	   {_id: 2, host: "{3}:27022", arbiterOnly:true, , priority: 0}
	 ]
});
# Replication 확인
mongo > rs.status()​

 

이번에는 2번 machine-primary 에서 수행하여 "rs1" Replica Set 을 정의합니다.

이렇게 하면 위 구성도처럼 6개의 노드가 각 Shard A/B 를 담당하게 됩니다.

이런 Shard 는 Mongos 가 확인할 수 있게 정의해야 합니다.

 

 

$ docker exec -it mongos mongosh -u root -p 1234 --port 27017
# Replication Set 2개에 대해 설정, Arbiter 는 제외한다. 
mongo > sh.addShard("rs0/{1}:27018,{2}:17018")
mongo > sh.addShard("rs1/{1}:17018,{2}:27018")
# 클러스터 상태 확인
mongo > sh.status()
# sharding 이 가능한 Database 생성
mongo > sh.enableSharding("test_database")
# collection 을 생성하고 sharding key 를 결정
mongo > sh.shardCollection("test_database.test", {sharding_key: "hashed"})
# sharding cluster 확인
mongo > sh.status()
# 위 데이터베이스에 접속하기 위한 user 생성
mongo > use test_database
mongo > db.createUser({
    user: "${USER}",
    pwd: "${PASSWORD}}",
    roles: [{role: "readWrite", db: "test_database"}]
})
# 유저가 생성되었는지 확인
mongo > db.getUsers()

 

위에서 지정한 sharding_key:"hashed" 로 sharding_key 라는 field 를

hashed 방식으로 shard key 로 사용하겠다 지정한 것입니다.

실제로 sharding_key 를 차후 사용할 field 의 이름이 됩니다.

 

이렇게 하면 MongoDB Sharded Cluster 설정은 완료되었습니다.

이후 생성한 db 에 sharding_key 라는 field 를 포함하여 데이터를 넣으면 각 shard 로 분할되는 것을 확인하실 수 있습니다.

 

만약 cluster 생성이 거절된다면 아래의 code block 을 참고해주세요.

 

 

# 각 priamry 에서 Arbiter 제거
$ docker exec -it mongo-rs0-primary mongosh -u root -p 1234 --port 27018
mongo > rs.remove("{3}:27021")

# 각 primary 에서 Arbiter 제거
$ docker exec -it mongo-rs1-primary mongosh -u root -p 1234 --port 27018
mongo > rs.remove("{3}:27022")

# Write Concern 1(primary 만 적용) 으로 조정
$ docker exec -it mongos mongosh -u root -p 1234 --port 27017
mongo > db.adminCommand({ setDefaultRWConcern: 1, defaultWriteConcern: { w: 1 } })

# 각 priamry 에서 Arbiter 다시 추가
$ docker exec -it mongo-rs0-primary mongosh -u root -p 1234 --port 27018
mongo > rs.addArb("{3}:27021")

# 각 priamry 에서 Arbiter 다시 추가
$ docker exec -it mongo-rs1-primary mongosh -u root -p 1234 --port 27018
mongo > rs.addArb("{3}:27022")

 

앞서 언급했듯 Arbiter 가 Write Concern 의 이유로 올라가지 않는다면 (Sharded Cluster 생성이 거절된다면)

Primary 에서 Arbiter 를 제거한 뒤 Mongos Write Concern 옵션 수정 후

Arbiter 를 다시 추가하여 Sharded Cluster 설정을 한다면 정상 기동이 가능합니다.

 

 

MongoDB Sharded Cluster 대량의 데이터를 효율적으로 처리할 있는 강력한 솔루션입니다.

Sharding Replication 통해 데이터의 가용성과 내결함성을 높이며, 성능을 극대화합니다.

꽤 간편한 방법으로 구성하고 솔루션 레벨에서 지원하는 Sharding 기능들을 사용함으로써 편리하게 사용할 수 있습니다.

자세한 내용은 MongoDB 공식 문서를 참고해주세요!

 

끝!

 

 

 

참고

https://liltdevs.tistory.com/216

 

MongoDB 총 정리 (Index, Transaction, Lock, Replication 등)

MongoDB문서(Document) 데이터베이스로 Key:Value 쌍으로 이뤄져있고 이는 JSON 객체와 유사.필드에는 다른 문서, 배열, 문서 배열 등이 포함될 수 있음문서 사용에 대한 장점Document 는 다양한 프로그래밍

liltdevs.tistory.com

 

https://www.mongodb.com/ko-kr/docs/manual/sharding/

 

샤딩 - MongoDB 매뉴얼 v7.0

샤딩은 데이터를 여러 머신에 분산하는 방법입니다. MongoDB는 샤딩을 사용하여 대규모 데이터 세트와 높은 처리량 작업의 배포를 지원합니다.대규모 데이터 세트 또는 높은 처리량의 애플리케이

www.mongodb.com

 

Comments