MongoDB Shard Cluster - 샤드 클러스터 구성

Share

Last Updated on 9월 2, 2023 by Jade(정현호)

안녕하세요  
이번 포스팅에서는 MongoDB의 Shard Cluster(샤드 클러스터) 구성에 대해서 확인해보려고 합니다.             

샤딩 및 샤드 클러스터

샤딩은 대용량 데이터베이스 또는 데이터에 대해서 여러 시스템에 데이터를 저장, 처리할 수 있도록 처리 또는 배포하는 방법입니다.

가령 데이터 세트가 크거나 처리량이 많은 애플리케이션을 사용하는 데이터베이스 시스템은 단일 서버의 용량에 문제가 될 수 있습니다. 또는 쿼리의 처리가 늦거나 쿼리 요청이 많다면 서버의 CPU 사용량이 많이 증가할 수 있으며, 시스템의 메모리(RAM) 또는 설정된 캐시(버퍼풀) 크기보다 더 큰 작업 세트 크기는 많은 디스크 I/O를 유발할 수도 있습니다.

그래서 대용량 데이터를 다루는 여러 방안 중에 하나가 샤딩 이라는 기술이며, MongoDB에서는 샤딩을 구현(적용) 하려면 Shard Cluster(샤드 클러스터)를 통해서 사용할 수 있으며, 샤드 클러스터는 MongoDB의 주요한 핵심 기능 또는 메인 기능이라고 할 수 있습니다. MongoDB는 샤딩을 통해 수평 스케일링을 지원합니다.

[mongodb.com/docs/manual/sharding]

MongoDB의 샤드 클러스터는 다음과 같은 구성 요소로 구성됩니다

  • shard : shard 또는 shard server 로 부르며, 샤드 서버는 실제 데이터를 저장하고 있는 데이터 노드(or 데이터 세트) 역할을 하며, 1개 이상의 ReplicaSet이 필요 합니다.
  • mongos: 쿼리 라우터 역할을 통해서 클라이언트 응용 프로그램과 샤드 클러스터 간의 인터페이스를 제공합니다. MongoDB 4.4부터 mongos는 지연 시간을 최소화하기 위해 Hedged Reads를 지원하며, 1개 이상의 mongos 가 필요 합니다.
  • config server: 샤드 클러스터에 대한 메타데이터 및 구성 설정 정보가 저장하며, 1개의 ReplicaSet 으로 구성됩니다.


일반적인 Production 환경에서는 다음과 같은 컴포넌트 별로 고가용성을 위한 다수의 구성이 요구됩니다.

  • Config Server를 3개 멤버의 ReplicaSet 으로 배포
  • 각 샤드 서버를 3 멤버의 ReplicaSet 으로 배포
  • 하나 이상의 mongos 라우터 배포

그래서 그림으로 표현하면 아래와 다음과 같은 구성의 형태가 되게 됩니다.

[mongodb.com/docs/manual/core/sharded-cluster-components]

포스팅에서는 테스트/학습의 목적으로 구성하기 위해서 1개의 단일 물리 시스템에서 포트를 다르게 설정하여 위와 같은 구성을 진행하였습니다.

 

Development 환경에서는 다음과 같이 최소의 컴포넌트 수를 통해서 샤드 클러스터를 구성할 수도 있습니다.

  • mongos 인스턴스 1개
  • 1개의 ReplicaSet으로 구성된 Shard 서버
  • ReplicaSet 으로 구성된 config server

이러한 Non-Production(Development) 에서의 샤드 클러스터 구성에 대한 이미지는 다음과 같습니다.

[mongodb.com/docs/manual/core/sharded-cluster-components]



[참고] 포스팅에서 사용한 버전 정보
OS : RockyLinux 8.7
MongoDB : 5.0.18
            

OS 사전 환경 구성

Transparent Huge Page(THP) 옵션 비활성화

Transparent Huge Page(THP) 기능 비활성화가 필요하며 서비스를 생성하여 진행하겠습니다.

[참고] 포스팅에서는 OS root 유저를 사용하며, SELinux 는 비활성화 상태로 진행합니다.

아래와 같은 경로에 파일을 vi 및 기타 편집기로 생성합니다.
vi /etc/systemd/system/disable-transparent-huge-pages.service

##### 아래 내용으로 작성

[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=mongod.service

[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo 'never' >/sys/kernel/mm/transparent_hugepage/enabled && echo 'never' >/sys/kernel/mm/transparent_hugepage/defrag"

[Install]
WantedBy=basic.target


파일 작성이 완완료되었다면아래와 같이 서비스를 시작합니다.

systemctl daemon-reload
systemctl enable disable-transparent-huge-pages
systemctl start disable-transparent-huge-pages


THP 기능이 비활성화 되었는지는 아래와 같이 확인합니다.

cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]


cat /sys/kernel/mm/transparent_hugepage/defrag
always defer defer+madvise madvise [never]

never 에 [] 으로 선택되어 있다면 비활성화 된 상태를 의미합니다.
           

Prerequisites OS Package

MongoDB 실행에 필요한 필요 OS 패키지를 설치합니다.

yum install libcurl openssl xz-libs

              

Ulimit 수정

ulimit 의 open files 값이 64000 미만이면 MongoDB 시작 오류가 발생될 수 있으므로 설정이 필요하며, 또한 권장되는 nproc 값에 대해서도 수정하도록 하겠습니다.

vi /etc/security/limits.conf


## 아래 내용 입력

mongod soft nofile 64000
mongod hard nofile 64000

mongod hard nproc 64000
mongod hard nproc 64000



포스팅에서는 OS root 유저로 실행을 진행하기 때문에 별도의 OS mongod 그룹 및 유저를 생성하지 않았으나, systemd 를 통해서 mongodb의 실행 유저를 일반 유저인 mongod(또는 mongo) 로 사용할 경우 OS 사전 작업 단계에서 아래와 같이 유저를 생성하시면 됩니다.

groupadd mongodb

useradd -M -s /usr/sbin/nologin -g mongodb mongodb 

-M 옵션을 사용해서 홈디렉토리를 생성하지 않고,
-s /bin/false 혹은 /sbin/nologin 옵션을 사용해서 유저의 로그인쉘을 사용할 수 없게 하는 것입니다.

즉 mongodb 이라는 유저는 MongoDB 데몬을 실행하기 위한 유저이고
서버의 보안강화 측면에서 외부에서 mongodb 유저로 쉘 로그인은 필요가 없습니다.
                    

샤드 클러스터 구성

포트 및 디렉토리 경로 정보

포스팅에서 사용한 포트 정보 및 디렉토리 경로 정보입니다.

  • config server
    Port : 27031 / 27032 / 27033
    디렉토리 :
    /usr/local/mongodb/config_server/data_27031
    /usr/local/mongodb/config_server/data_27032
    /usr/local/mongodb/config_server/data_27033

  • shard server
    Port :
    replset1 - 27021 / 27022 / 27023(Arbiter)
    replset2 - 27024 / 27025 / 27026(Arbiter)
    replset3 - 27027 / 27028 / 27029(Arbiter)

    디렉토리 :
    replset1
    /usr/local/mongodb/shard_server/data_27021
    /usr/local/mongodb/shard_server/data_27022
    /usr/local/mongodb/shard_server/data_27023

    replset2
    /usr/local/mongodb/shard_server/data_27024
    /usr/local/mongodb/shard_server/data_27025
    /usr/local/mongodb/shard_server/data_27026

    replset3
    /usr/local/mongodb/shard_server/data_27027
    /usr/local/mongodb/shard_server/data_27028
    /usr/local/mongodb/shard_server/data_27029

  • mongos
    Port : 27041

    디렉토리 :
    /usr/local/mongodb/mongos/mongos_27041

                  

MongoDB 다운로드 및 구성

MongoDB는 5.0.18 버전을 사용하였으며 다음과 같이 다운로드 및 압축을 해제합니다.
포스팅에서는 /usr/local 경로 아래에 파일을 위치하였습니다.

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-5.0.18.tgz

tar zxvf mongodb-linux-x86_64-rhel80-5.0.18.tgz -C /usr/local


사용 편의성 및 관리용의성을 위해서 심볼릭 링크를 생성하도록 하겠습니다.

cd /usr/local/
ln -s mongodb-linux-x86_64-rhel80-5.0.18 mongodb


OS PATH 변수를 설정하도록 하겠습니다.

vi ~/.bash_profile

## 아래 변수 추가

export PATH=$PATH:/usr/local/mongodb/bin


파일에 내용을 추가하였다면, 다음과 같이 파일을 다시 읽어 적용합니다.

source ~/.bash_profile

            

config server 구성

config server Replica Set으로 구성하도록 하겠습니다.

MongoDB 샤드클러스터 구성에서 config 서버로 사용되는 레플리카 셋 구성에는 다음과 같은 제한 사항이 적용됩니다.

  • arbiter가 없어야 합니다.
  • 지연된 멤버가 없어야 합니다.
  • 인덱스를 작성해야 합니다. 즉, 어떤 멤버도 members[n].buildIndexes 설정을 false로 설정해서는 안 됩니다.

그래서 Config 서버의 Replica Set의 멤버 중 하나는 arbiter 로 설정하지 않습니다.

config server 구성을 위한 데이터 저장 경로를 생성합니다.

mkdir -p /usr/local/mongodb/config_server/data_27031
mkdir -p /usr/local/mongodb/config_server/data_27032
mkdir -p /usr/local/mongodb/config_server/data_27033


config server 구동 합니다.

mongod --configsvr --replSet configrs \
--dbpath /usr/local/mongodb/config_server/data_27031 \
--logpath /usr/local/mongodb/config_server/data_27031/mongo_config.log --logappend \
--fork --port 27031 --bind_ip_all --directoryperdb

mongod --configsvr --replSet configrs \
--dbpath /usr/local/mongodb/config_server/data_27032 \
--logpath /usr/local/mongodb/config_server/data_27032/mongo_config.log --logappend \
--fork --port 27032 --bind_ip_all --directoryperdb

mongod --configsvr --replSet configrs \
--dbpath /usr/local/mongodb/config_server/data_27033 \
--logpath /usr/local/mongodb/config_server/data_27033/mongo_config.log --logappend \
--fork --port 27033 --bind_ip_all --directoryperdb


실행된 Config Server 중 하나의 서버에 접속하여 ReplicaSet 설정을 합니다.

## OS 에서 config server 접속
mongo --host 127.0.0.1 --port 27031


## config server 접속후 아래 명령어 수행
use admin

rs.initiate(
{
    _id : "configrs",
    configsvr : true,
    members : [
        { _id:0, host: "127.0.0.1:27031"},
        { _id:1, host: "127.0.0.1:27032"},
        { _id:2, host: "127.0.0.1:27033"}
    ]
}
)


구성된 config server ReplicaSet에 대한 정보는 config server에 접속하여 다음의 명령어를 통해서 확인합니다.

rs.hello()


keyfile을 사용하여 authorization 활성화하여 인증설정을 할 경우 동일한 keyfile을 사용해서 config 서버와 shard server를 시작해야 합니다.
keyfile 생성과 keyfile에 대한 내용은 아래 포스팅을 참조하시면 됩니다.


keyfile을 생성하였다면 config server 시작 시 keyfile 옵션은 다음과 같이 사용합니다.

mongod --configsvr --keyFile /경로/mongod.key --auth --clusterAuthMode keyFile \
....
....

         

Shard Server 구성

샤드 서버를 위해서 다음과 같이 ReplicaSet 3개 세트를 구성하도록 하겠습니다.

  • replset1 – 27021, 27022, 27023
  • replset2 – 27024, 27025, 27026
  • replset3 – 27027, 27028, 27029

ReplicaSet은 1개 Primary, 1개 Secondary, 1개 Arbiter 로 구성하도록 하겠습니다.

MongoDB ReplicaSet에 대한 추가적인 내용은 아래 포스팅을 확인하시면 됩니다.


data dir 를 생성합니다.

mkdir -p /usr/local/mongodb/shard_server/data_27021
mkdir -p /usr/local/mongodb/shard_server/data_27022
mkdir -p /usr/local/mongodb/shard_server/data_27023

mkdir -p /usr/local/mongodb/shard_server/data_27024
mkdir -p /usr/local/mongodb/shard_server/data_27025
mkdir -p /usr/local/mongodb/shard_server/data_27026

mkdir -p /usr/local/mongodb/shard_server/data_27027
mkdir -p /usr/local/mongodb/shard_server/data_27028
mkdir -p /usr/local/mongodb/shard_server/data_27029


Shard Server 시작합니다.

## Shard-1
mongod --shardsvr --replSet replset1 \
--dbpath /usr/local/mongodb/shard_server/data_27021 \
--logpath /usr/local/mongodb/shard_server/data_27021/mongo_shard.log --logappend \
--fork --port 27021 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset1 \
--dbpath /usr/local/mongodb/shard_server/data_27022 \
--logpath /usr/local/mongodb/shard_server/data_27022/mongo_shard.log --logappend \
--fork --port 27022 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset1 \
--dbpath /usr/local/mongodb/shard_server/data_27023 \
--logpath /usr/local/mongodb/shard_server/data_27023/mongo_shard.log --logappend \
--fork --port 27023 --bind_ip_all --directoryperdb 


## Shard-2
mongod --shardsvr --replSet replset2 \
--dbpath /usr/local/mongodb/shard_server/data_27024 \
--logpath /usr/local/mongodb/shard_server/data_27024/mongo_shard.log --logappend \
--fork --port 27024 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset2 \
--dbpath /usr/local/mongodb/shard_server/data_27025 \
--logpath /usr/local/mongodb/shard_server/data_27025/mongo_shard.log --logappend \
--fork --port 27025 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset2 \
--dbpath /usr/local/mongodb/shard_server/data_27026 \
--logpath /usr/local/mongodb/shard_server/data_27026/mongo_shard.log --logappend \
--fork --port 27026 --bind_ip_all --directoryperdb 


## Shard-3
mongod --shardsvr --replSet replset3 \
--dbpath /usr/local/mongodb/shard_server/data_27027 \
--logpath /usr/local/mongodb/shard_server/data_27027/mongo_shard.log --logappend \
--fork --port 27027 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset3 \
--dbpath /usr/local/mongodb/shard_server/data_27028 \
--logpath /usr/local/mongodb/shard_server/data_27028/mongo_shard.log --logappend \
--fork --port 27028 --bind_ip_all --directoryperdb 

mongod --shardsvr --replSet replset3 \
--dbpath /usr/local/mongodb/shard_server/data_27029 \
--logpath /usr/local/mongodb/shard_server/data_27029/mongo_shard.log --logappend \
--fork --port 27029 --bind_ip_all --directoryperdb 


keyfile을 사용하여 authorization 활성화하여 인증설정을 할 경우 동일한 keyfile을 사용해서 config 서버와 shard server를 시작해야 합니다.
keyfile 생성과 keyfile에 대한 내용은 아래 포스팅을 참조하시면 됩니다.


keyfile을 생성하였고 keyfile옵션을 사용할 경우 다음과 mongod 명령어를 다음과 같이 사용합니다.

mongod --shardsvr --keyFile /경로/mongod.key --auth --clusterAuthMode keyFile \
....
....


ReplicaSet을 설정하기 위해서 ReplicaSet 에서 1개 서버에 접속합니다.

mongo --host 127.0.0.1 --port 27021


1개 서버를 arbiter 로 변경(지정) 합니다. arbiter 노드가 아닌 Secondary 로 지정하여 사용하여도 됩니다.

use admin

rs.initiate(
    {
        _id : "replset1",
        members : [
            {_id : 0, host: "127.0.0.1:27021"},
            {_id : 1, host: "127.0.0.1:27022"},
            {_id : 2, host: "127.0.0.1:27023",arbiterOnly:true}
            ]
    }
)

{ "ok" : 1 }



위의 방법으로 나머지 2개 ReplicaSet도 변경합니다.

$ mongo --host 127.0.0.1 --port 27024

use admin

rs.initiate(
    {
        _id : "replset2",
        members : [
            {_id : 0, host: "127.0.0.1:27024"},
            {_id : 1, host: "127.0.0.1:27025"},
            {_id : 2, host: "127.0.0.1:27026",arbiterOnly:true}
            ]
    }
)

{ "ok" : 1 }

=========================================================================


$ mongo --host 127.0.0.1 --port 27027

use admin

rs.initiate(
    {
        _id : "replset3",
        members : [
            {_id : 0, host: "127.0.0.1:27027"},
            {_id : 1, host: "127.0.0.1:27028"},
            {_id : 2, host: "127.0.0.1:27029",arbiterOnly:true}
            ]
    }
)

{ "ok" : 1 }


위의 설정 변경을 완료 후 다음 명령어를 통해서 ReplicaSet 정보를 확인합니다.

rs.hello()



여기까지 진행이 되었다면 Config 서버 1Set(3개 서버), ReplicaSet 3개세트(총 9개 서버)가 구성된 상태가 되게 됩니다.
              

MongoS 실행

mongod 로 구동하였던 config server 와 shard server 와 달리 mongos 는 mongos 라는 바이너리 실행 파일을 통해서 실행합니다.

logpath 를 위해서 디렉토리를 생성합니다.

mkdir -p /usr/local/mongodb/mongos/mongos_27041


mongos 를 구동 합니다.

mongos --configdb configrs/127.0.0.1:27031,127.0.0.1:27032,127.0.0.1:27033 \
--logpath /usr/local/mongodb/mongos/mongos_27041/mongos.log --logappend \
--fork --port 27041 --bind_ip_all

              

샤드 클러스터에 추가

ReplicaSet 으로 구성한 Shard 서버를 클러스터에 추가하도록 하겠습니다.

mongos(router) 서버로 접속합니다. 포스팅에서는 mongos 포트를 27041 로 사용중입니다.

mongo --host 127.0.0.1 --port 27041


샤드 클러스터에 서버를 추가 시 다음과 같이 arbiter 노드를 제외하고 Primary 와 Secondary만 입력하면 됩니다.

sh.addShard("replset1/127.0.0.1:27021,127.0.0.1:27022")

sh.addShard("replset2/127.0.0.1:27024,127.0.0.1:27025")

sh.addShard("replset3/127.0.0.1:27027,127.0.0.1:27028")



샤드 클러스터에 추가가 완료되었다면 다음 명령어를 통해서 샤드 클러스터의 상태를 확인합니다.

sh.status()


여기까지 완료되었다면 MongoDB 샤드 클러스터 구성이 완료된 상태입니다.
            

샤드 활성화 및 샤딩 테스트

mongos로 접속합니다.

mongo --host 127.0.0.1 --port 27041


shard cluster 활성화는 샤드로 사용할 데이터베이스에 대해서 한번은 실행이 반드시 필요 합니다.
샤드로 사용할 데이터베이스명을 입력해서 enable 을 해야 합니다.
포스팅에서는 tdb 라는 데이터베이스에 대해서 지정하였습니다.

sh.enableSharding("tdb")


샤딩할 Collection 을 입력하고 샤드키를 선정합니다.

sh.shardCollection("tdb.employees",{empno: "hashed"})


여기까지 완료되었다면 샤드 클러스터 상태 정보를 확인해 봅니다.

sh.status()



실제 데이터를 입력하여 샤딩이 되어 데이터가 입력되는지를 확인해보도록 하겠습니다.(100건 입력)

use tdb

for(var a=1; a< 100; a++) db.employees.insert({ empno :a })


다시 샤드 클러스터의 상태 정보를 확인합니다.

sh.status()


db.collection.getShardDistribution() 메서드를 사용하여 특정 콜렉션의 분할 상태를 확인할 수 있습니다. 이 메서드는 콜렉션의 데이터가 어떤 샤드에 어떻게 분산되었는지 확인할 수 있습니다.

use tdb

db.employees.getShardDistribution()


위의 명령을 실행하면 각 샤드에 대한 정보와 해당 샤드에 저장된 청크(chunk)의 범위, 데이터의 분포 등을 확인할 수 있습니다. 샤드 클러스터에서 샤딩된 컬렉션의 분할 상태와 관련된 자세한 정보를 제공합니다.


이번 포스팅은 여기서 마무리하도록 하겠으며, MongoDB Shard Cluster에 대한 더 자세한 내용은 별도의 포스팅에서 이어 가도록 하겠습니다.
                 

Reference

Reference URL
mongodb.com/docs/sharding
mongodb.com/docs/sharded-cluster-components
mongodb.com/docs/sharded-cluster-config-servers



연관된 다른 글

 

 

 

 

            

0
글에 대한 당신의 생각을 기다립니다. 댓글 의견 주세요!x