IT/WSL

[mongo] 샤딩 클러스터 실습(feat. docker-compose)

상짱 2025. 1. 14. 00:46
반응형

1. docker-compose-mongo-sharding-cluster.yml 작성

version: '3.8'

services:
  # ------------------- SERVER-1
  config1:
    image: mongo:4.4
    container_name: mongo-config1
    command: --configsvr --replSet configReplSet --port 27019
    ports:
      - "17019:27019"
    volumes:
      - ./mongo/server1/data/config:/data/configdb

  shard1:
    image: mongo:4.4
    container_name: mongo-shard1
    command: --shardsvr --replSet shardReplSet --port 27018
    ports:
      - "17018:27018"
    volumes:
      - ./mongo/server1/data/shard:/data/db

  mongos1:
    image: mongo:4.4
    container_name: mongo-mongos1
    #    command: mongos --configdb configReplSet/127.0.0.1:17019,127.0.0.1:27019,127.0.0.1:37019
    command: mongos --configdb configReplSet/mongo-config1:27019,mongo-config2:27019,mongo-config3:27019
    ports:
      - "17017:27017"

# ------------------- SERVER-2
  config2:
    image: mongo:4.4
    container_name: mongo-config2
    command: --configsvr --replSet configReplSet --port 27019
    ports:
      - "27019:27019"
    volumes:
      - ./mongo/server2/data/config:/data/configdb

  shard2:
    image: mongo:4.4
    container_name: mongo-shard2
    command: --shardsvr --replSet shardReplSet --port 27018
    ports:
      - "27018:27018"
    volumes:
      - ./mongo/server2/data/shard:/data/db

  mongos2:
    image: mongo:4.4
    container_name: mongo-mongos2
#    command: mongos --configdb configReplSet/127.0.0.1:17019,127.0.0.1:27019,127.0.0.1:37019
    command: mongos --configdb configReplSet/mongo-config1:27019,mongo-config2:27019,mongo-config3:27019
    ports:
      - "27017:27017"

# --------------- SERVER-3
  config3:
    image: mongo:4.4
    container_name: mongo-config3
    command: --configsvr --replSet configReplSet --port 27019
    ports:
      - "37019:27019"
    volumes:
      - ./mongo/server3/data/config:/data/db

  shard3:
    image: mongo:4.4
    container_name: mongo-shard3
    command: --shardsvr --replSet shardReplSet --port 27018
    ports:
      - "37018:27018"
    volumes:
      - ./mongo/server3/data/shard:/data/db

  mongos3:
    image: mongo:4.4
    container_name: mongo-mongos3
    #    command: mongos --configdb configReplSet/127.0.0.1:17019,127.0.0.1:27019,127.0.0.1:37019
    command: mongos --configdb configReplSet/mongo-config1:27019,mongo-config2:27019,mongo-config3:27019
    ports:
      - "37017:27017"

 
- Config 컨테이너 : --configsvr 플래그 사용, configReplSet 복제 세트 초기화, 포트 27019 
- Shard 컨테이너 : --shardsvr 플래그 사용, shardReplSet 복제 세트 초기화, 포트 27018
- Mongos Routers 컨테이너 : --configdb 플래그 사용, 클러스터의 메타데이터를 가져오는 역할, 포트 27017
 
- 도커 컨테이너 실행

#-- 컨테이너 실행
$ docker compose -f docker-compose-mongo-shard-cluster.yml up -d

#-- 확인
$ docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                                                      NAMES
22bbc072b202   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 27 seconds   27017/tcp, 0.0.0.0:17018->27018/tcp, :::17018->27018/tcp   mongo-shard1
42a0e4902c0d   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   0.0.0.0:17017->27017/tcp, :::17017->27017/tcp              mongo-mongos1
feb0ef62e227   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   27017/tcp, 0.0.0.0:37019->27019/tcp, :::37019->27019/tcp   mongo-config3
f27548dc12a8   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   27017/tcp, 0.0.0.0:17019->27019/tcp, :::17019->27019/tcp   mongo-config1
63fede16525d   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   0.0.0.0:27017->27017/tcp, :::27017->27017/tcp              mongo-mongos2
9c7e13cb1409   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 27 seconds   0.0.0.0:37017->27017/tcp, :::37017->27017/tcp              mongo-mongos3
17c457068ed5   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 27 seconds   27017/tcp, 0.0.0.0:27019->27019/tcp, :::27019->27019/tcp   mongo-config2
2d69cb8b5e9b   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 27 seconds   27017/tcp, 0.0.0.0:37018->27018/tcp, :::37018->27018/tcp   mongo-shard3
f340f2711616   mongo:4.4   "docker-entrypoint.s…"   29 seconds ago   Up 28 seconds   27017/tcp, 0.0.0.0:27018->27018/tcp, :::27018->27018/tcp   mongo-shard2

 
- Config 컨테이너 / Replica Set 초기화

$ docker exec -it mongo-config1 mongo --port 27019
rs.initiate({
  _id: "configReplSet",
  configsvr: true,
  members: [
    { _id: 0, host: "mongo-config1:27019" },
    { _id: 1, host: "mongo-config2:27019" },
    { _id: 2, host: "mongo-config3:27019" }
  ]
})

--- 결과
{
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1736780702, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0)
}

--- 상태 확인
configReplSet:SECONDARY> rs.status()
{
        "set" : "configReplSet",
        "date" : ISODate("2025-01-13T15:06:07.244Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "configsvr" : true,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "votingMembersCount" : 3,
        "writableVotingMembersCount" : 3,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1736780766, 1),
                        "t" : NumberLong(1)
                },
                "lastCommittedWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1736780766, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                "appliedOpTime" : {
                        "ts" : Timestamp(1736780766, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1736780766, 1),
                        "t" : NumberLong(1)
                },
                "lastAppliedWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                "lastDurableWallTime" : ISODate("2025-01-13T15:06:06.955Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(1736780712, 4),
        "electionCandidateMetrics" : {
                "lastElectionReason" : "electionTimeout",
                "lastElectionDate" : ISODate("2025-01-13T15:05:12.585Z"),
                "electionTerm" : NumberLong(1),
                "lastCommittedOpTimeAtElection" : {
                        "ts" : Timestamp(0, 0),
                        "t" : NumberLong(-1)
                },
                "lastSeenOpTimeAtElection" : {
                        "ts" : Timestamp(1736780702, 1),
                        "t" : NumberLong(-1)
                },
                "numVotesNeeded" : 2,
                "priorityAtElection" : 1,
                "electionTimeoutMillis" : NumberLong(10000),
                "numCatchUpOps" : NumberLong(0),
                "newTermStartDate" : ISODate("2025-01-13T15:05:12.649Z"),
                "wMajorityWriteAvailabilityDate" : ISODate("2025-01-13T15:05:13.188Z")
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "mongo-config1:27019",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 180,
                        "optime" : {
                                "ts" : Timestamp(1736780766, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:06:06Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "Could not find member to sync from",
                        "electionTime" : Timestamp(1736780712, 1),
                        "electionDate" : ISODate("2025-01-13T15:05:12Z"),
                        "configVersion" : 1,
                        "configTerm" : 1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "mongo-config2:27019",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 64,
                        "optime" : {
                                "ts" : Timestamp(1736780765, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1736780765, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:06:05Z"),
                        "optimeDurableDate" : ISODate("2025-01-13T15:06:05Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "lastHeartbeat" : ISODate("2025-01-13T15:06:06.618Z"),
                        "lastHeartbeatRecv" : ISODate("2025-01-13T15:06:05.627Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "mongo-config1:27019",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : 1
                },
                {
                        "_id" : 2,
                        "name" : "mongo-config3:27019",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 64,
                        "optime" : {
                                "ts" : Timestamp(1736780765, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1736780765, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:06:05Z"),
                        "optimeDurableDate" : ISODate("2025-01-13T15:06:05Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:06:06.955Z"),
                        "lastHeartbeat" : ISODate("2025-01-13T15:06:06.617Z"),
                        "lastHeartbeatRecv" : ISODate("2025-01-13T15:06:05.625Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "mongo-config1:27019",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : 1
                }
        ],
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1736780702, 1),
                "electionId" : ObjectId("7fffffff0000000000000001")
        },
        "lastCommittedOpTime" : Timestamp(1736780766, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1736780766, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1736780766, 1)
}

 
- Shard 컨테이너 / Replica Set 초기화

$ docker exec -it mongo-shard1 mongo --port 27018
rs.initiate({
  _id: "shardReplSet",
  members: [
    {_id: 0, host: "mongo-shard1:27018"},
    {_id: 1, host: "mongo-shard2:27018"},
    {_id: 2, host: "mongo-shard3:27018"}
  ]
})

--- 결과
{ "ok" : 1 }

--- 상태 확인
shardReplSet:SECONDARY> rs.status()
{
        "set" : "shardReplSet",
        "date" : ISODate("2025-01-13T15:08:06.269Z"),
        "myState" : 1,
        "term" : NumberLong(1),
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "heartbeatIntervalMillis" : NumberLong(2000),
        "majorityVoteCount" : 2,
        "writeMajorityCount" : 2,
        "votingMembersCount" : 3,
        "writableVotingMembersCount" : 3,
        "optimes" : {
                "lastCommittedOpTime" : {
                        "ts" : Timestamp(1736780876, 1),
                        "t" : NumberLong(1)
                },
                "lastCommittedWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                "readConcernMajorityOpTime" : {
                        "ts" : Timestamp(1736780876, 1),
                        "t" : NumberLong(1)
                },
                "readConcernMajorityWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                "appliedOpTime" : {
                        "ts" : Timestamp(1736780876, 1),
                        "t" : NumberLong(1)
                },
                "durableOpTime" : {
                        "ts" : Timestamp(1736780876, 1),
                        "t" : NumberLong(1)
                },
                "lastAppliedWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                "lastDurableWallTime" : ISODate("2025-01-13T15:07:56.310Z")
        },
        "lastStableRecoveryTimestamp" : Timestamp(1736780866, 4),
        "electionCandidateMetrics" : {
                "lastElectionReason" : "electionTimeout",
                "lastElectionDate" : ISODate("2025-01-13T15:07:46.239Z"),
                "electionTerm" : NumberLong(1),
                "lastCommittedOpTimeAtElection" : {
                        "ts" : Timestamp(0, 0),
                        "t" : NumberLong(-1)
                },
                "lastSeenOpTimeAtElection" : {
                        "ts" : Timestamp(1736780855, 1),
                        "t" : NumberLong(-1)
                },
                "numVotesNeeded" : 2,
                "priorityAtElection" : 1,
                "electionTimeoutMillis" : NumberLong(10000),
                "numCatchUpOps" : NumberLong(0),
                "newTermStartDate" : ISODate("2025-01-13T15:07:46.290Z"),
                "wMajorityWriteAvailabilityDate" : ISODate("2025-01-13T15:07:46.393Z")
        },
        "members" : [
                {
                        "_id" : 0,
                        "name" : "mongo-shard1:27018",
                        "health" : 1,
                        "state" : 1,
                        "stateStr" : "PRIMARY",
                        "uptime" : 297,
                        "optime" : {
                                "ts" : Timestamp(1736780876, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:07:56Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "syncSourceHost" : "",
                        "syncSourceId" : -1,
                        "infoMessage" : "",
                        "electionTime" : Timestamp(1736780866, 1),
                        "electionDate" : ISODate("2025-01-13T15:07:46Z"),
                        "configVersion" : 1,
                        "configTerm" : -1,
                        "self" : true,
                        "lastHeartbeatMessage" : ""
                },
                {
                        "_id" : 1,
                        "name" : "mongo-shard2:27018",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 30,
                        "optime" : {
                                "ts" : Timestamp(1736780876, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1736780876, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:07:56Z"),
                        "optimeDurableDate" : ISODate("2025-01-13T15:07:56Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "lastHeartbeat" : ISODate("2025-01-13T15:08:06.253Z"),
                        "lastHeartbeatRecv" : ISODate("2025-01-13T15:08:04.845Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "mongo-shard1:27018",
                        "syncSourceId" : 0,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : -1
                },
                {
                        "_id" : 2,
                        "name" : "mongo-shard3:27018",
                        "health" : 1,
                        "state" : 2,
                        "stateStr" : "SECONDARY",
                        "uptime" : 30,
                        "optime" : {
                                "ts" : Timestamp(1736780876, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDurable" : {
                                "ts" : Timestamp(1736780876, 1),
                                "t" : NumberLong(1)
                        },
                        "optimeDate" : ISODate("2025-01-13T15:07:56Z"),
                        "optimeDurableDate" : ISODate("2025-01-13T15:07:56Z"),
                        "lastAppliedWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "lastDurableWallTime" : ISODate("2025-01-13T15:07:56.310Z"),
                        "lastHeartbeat" : ISODate("2025-01-13T15:08:06.253Z"),
                        "lastHeartbeatRecv" : ISODate("2025-01-13T15:08:05.340Z"),
                        "pingMs" : NumberLong(0),
                        "lastHeartbeatMessage" : "",
                        "syncSourceHost" : "mongo-shard2:27018",
                        "syncSourceId" : 1,
                        "infoMessage" : "",
                        "configVersion" : 1,
                        "configTerm" : -1
                }
        ],
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1736780876, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1736780876, 1)
}


- Mongos 컨테이너 / Shard 추가

$ docker exec -it mongo-mongos1 mongo --port 27017
sh.addShard("shardReplSet/mongo-shard1:27018,mongo-shard2:27018,mongo-shard3:27018")

--- 결과
{
        "shardAdded" : "shardReplSet",
        "ok" : 1,
        "operationTime" : Timestamp(1736780964, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1736780964, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

 
- 데이터베이스 / 유저 생성 / 데이터베이스 샤딩 활성화

$ docker exec -it mongo-mongos1 mongo --port 27017
use testdb;
sh.enableSharding("testdb")

--- 결과
{
        "ok" : 1,
        "operationTime" : Timestamp(1736781357, 6),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1736781357, 6),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

--- 유저 생성
use testdb;
db.createUser({
  user: "test",
  pwd: "1!test",
  roles: [{ role: "readWrite", db: "testdb" }]
})

--- 유저 확인
use testdb;
db.getUsers();

 
- 컬렉션 샤딩 / 샤드 키 지정
- 샤드 키는 쿼리 패턴과 데이터 분포를 고려해야 한다.
- 샤드 키를 선택할 때는 고유한 값이 너무 많거나 적은 필드는 피하는 것이 좋다.

# db.collection_nm.createIndex({ shardKeyField: 1 })
# sh.shardCollection("testdb.collection_nm", { shardKeyField: 1 })

ex)
// 샤드 키 설정 (timestamp를 샤드 키로 사용)
sh.enableSharding("testdb");  // 데이터베이스 샤딩 활성화
db.testLog.createIndex({ "timestamp": 1 });  // timestamp에 인덱스를 생성 (샤드 키로 사용하려면 인덱스가 필요)
sh.shardCollection("testdb.testLog", { "timestamp": 1 });  // timestamp를 샤드 키로 설정

--- 샤드 키 확인
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("67852ba8fe5cc05de06066d1")
  }
  shards:
        {  "_id" : "shardReplSet",  "host" : "shardReplSet/mongo-shard1:27018,mongo-shard2:27018,mongo-shard3:27018",  "state" : 1 }
  active mongoses:
        "4.4.29" : 3
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours:
                No recent migrations
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                shardReplSet    1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "testdb",  "primary" : "shardReplSet",  "partitioned" : true,  "version" : {  "uuid" : UUID("6210f383-a255-42a8-a6d0-86a2bb4e859f"),  "lastMod" : 1 },  "lastMovedTimestamp" : Timestamp(1736781357, 1) }
                testdb.testLog
                        shard key: { "timestamp" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                shardReplSet    1
                        { "timestamp" : { "$minKey" : 1 } } -->> { "timestamp" : { "$maxKey" : 1 } } on : shardReplSet Timestamp(1, 0)

 
- 테스트

$ docker exec -it mongo-mongos1 mongo --port 27017
use testdb;
db.testLog.insertOne({ "test": "test1"})
db.testLog.insertOne({ "test":"test1111111" })
db.testLog.find()

$ docker exec -it mongo-mongos3 mongo --port 27017
use testdb;
db.testLog.find()

 
- 별첨

# 사용자 인증이 필요한 mongoDB 접속 / testdb 데이터베이스에서 test 사용자 인증을 시도
$ docker exec -it mongo-mongos1 mongo -u test -p  --authenticationDatabase "testdb"

# 인증 없이 mongoDB 접속
$ docker exec -it mongo-mongos1 mongo --port 27017

# MongoDB 인스턴스에서 인증이 활성화 확인
# [mongod.conf] - security.authorization: "disabled" (default)
# [mongod.conf] - security.authorization: "enabled" 로 활성화
$ docker exec -it mongo-mongos1 cat /etc/mongod.conf
$ docker exec -it mongo-mongos1 cat /etc/mongod.conf.orig
반응형