MongoDB Replicated sharded cluster

샤딩이란

데이터를 여러 대의 디비에 분산시켜 저장하는 기술을 말한다.

몽고디비는 샤딩을 자동으로 처리해준다.


샤딩을 ReplicaSet에 구성하기

Config 서버

샤딩에 필요한 메타데이터가 저장되며, Config 서버 수는 1 또는 3개만 가능하다.

서버 수가 불일치 하다면, "BadValue need either 1 or 3 configdbs" 오류 메시지가 출력된다.

configsvr=true를 해준다.

# mongod.conf
configsvr=true
#where to log
logpath=/var/lib/mongo/config1/mongod.log
logappend=false
# fork and run in background
fork=true
port=20001
dbpath=/var/lib/mongo/config1
smallfiles=true
# location of pidfile
pidfilepath=/var/run/mongodb/mongod_config1.pid
# Listen to local interface only. Comment out to listen on all interfaces.
bind_ip=127.0.0.1
# Disables write-ahead journaling
nojournal=true
# Disable data file preallocation.
noprealloc=true
# maximum size in megabytes for replication operation log
oplogSize=1

Config 서버 실행

1
$ mongod --config /etc/mongod_conf1.conf


Mongos 서버

데이터를 라우팅 시켜주는 서버이며, 여러 대를 실행 시킬 수 있다.

샤딩 데이터를 디비에 읽고 쓰기 위해서 Mongod가 아닌 Mongos 서버에 연결해야 한다.

샤당할 서버를 등록하기에 앞서 ReplicaSet 구성하기를 참고하여 first와 second군을 만들어 둔다.

configdb에 Config서버를 추가하고, chunkSize=1로 설정해 샤딩테스트를 용이하게 한다.

# mongod.conf
configdb=localhost:20001
chunkSize = 1
#where to log
logpath=/var/lib/mongo/mongos/mongod.log
logappend=false
# fork and run in background
fork=true
port=27001
# location of pidfile
pidfilepath=/var/run/mongodb/mongos.pid
# Listen to local interface only. Comment out to listen on all interfaces.
bind_ip=127.0.0.1
view raw mongos.conf hosted with ❤ by GitHub

Mongos 서버 실행과 샤딩 정보 등록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
## Mongos 서버 실행
$ mongos -f /etc/mongos.conf
 
## Mongos에 접속
$ mongo localhost:27001/admin
 
## 샤딩서버 등록
## localhost:10003과 localhost:10006은 Arbiter 이므로 추가해도 등록되지 않으니, 추가해도 되고 안해도 된다.
mongos> db.runCommand( { addShard : "first/localhost:10001,localhost:10002,localhost:10003" } )
{ "shardAdded" : "first", "ok" : 1 }
mongos> db.runCommand( { addShard : "second/localhost:10004,localhost:10005,localhost:10006" } )
{ "shardAdded" : "second", "ok" : 1 }
 
## 샤딩 리스트 확인
mongos> db.runCommand({listShards:1})
{
        "shards" : [
                {
                        "_id" : "first",
                        "host" : "first/localhost:10001,localhost:10002"
                },
                {
                        "_id" : "second",
                        "host" : "second/localhost:10004,localhost:10005"
                }
        ],
        "ok" : 1
}
 
## 샤딩할 디비 등록
mongos> db.runCommand( { enableSharding : "test" } )
{ "ok" : 1 }
 
## 샤드키 설정
## 이미 설정하였다면 넘어가자
mongos> use test
switched to db test
mongos> db.test_collection.ensureIndex({number:1})
{
        "raw" : {
                "first/localhost:10001,localhost:10002" : {
                        "createdCollectionAutomatically" : true,
                        "numIndexesBefore" : 1,
                        "numIndexesAfter" : 2,
                        "ok" : 1
                }
        },
        "ok" : 1
}
 
## 샤딩할 컬렉션과 샤드키 등록
mongos> use admin
switched to db admin
mongos> db.runCommand( { shardCollection : "test.test_collection", key : {"number":1} })
{ "collectionsharded" : "test.test_collection", "ok" : 1 }

샤딩이 잘 되는지 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
## Mongos 서버에 연결해야 한다.
## 10만개를 생성해 넣어보자.
mongos> use test
switched to db test
mongos> for (var i = 0; i < 100000; ++i) db.test_collection.save({number:i})
WriteResult({ "nInserted" : 1 })
 
## 각 서버에 어떻게 데이터가 분산되어 있는지 확인해 보자.
## 샤드키(number)값의 범위에 따라 분산되어 있다.
mongos> db.printShardingStatus()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "version" : 4,
        "minCompatibleVersion" : 4,
        "currentVersion" : 5,
        "clusterId" : ObjectId("53a9318e6d2c219bb5966c5f")
}
  shards:
        "_id" : "first""host" : "first/localhost:10001,localhost:10002" }
        "_id" : "second""host" : "second/localhost:10004,localhost:10005" }
  databases:
        "_id" : "admin""partitioned" : false"primary" : "config" }
        "_id" : "test""partitioned" : true"primary" : "first" }
                test.test_collection
                        shard key: { "number" : 1 }
                        chunks:
                                first   3
                                second  3
                        { "number" : { "$minKey" : 1 } } -->> { "number" : 0 } on : first Timestamp(4, 0)
                        { "number" : 0 } -->> { "number" : 13026 } on : first Timestamp(3, 1)
                        { "number" : 13026 } -->> { "number" : 38291 } on : first Timestamp(5, 0)
                        { "number" : 38291 } -->> { "number" : 60483 } on : second Timestamp(5, 1)
                        { "number" : 60483 } -->> { "number" : 86544 } on : second Timestamp(4, 4)
                        { "number" : 86544 } -->> { "number" : { "$maxKey" : 1 } } on : second Timestamp(4, 5)
 
 
 
## first 서버에 연결해 몇 개가 쌓여있는지 확인
$ mongo localhost:10001/admin
MongoDB shell version: 2.6.2
connecting to: localhost:10001/admin
first:PRIMARY> use test
switched to db test
first:PRIMARY> db.test_collection.count()
38291
 
## number:0은 first에 있고, number:38291은  second에 분산되어 있다고 했다.
## 실제로 그런지 확인해 보자. 정상이군
first:PRIMARY> db.test_collection.find({number:0})
{ "_id" : ObjectId("53a937ecc09ddce1f1cef931"), "number" : 0 }
first:PRIMARY> db.test_collection.find({number:38291})
 
## second 서버에 연결해 몇 개가 쌓여있는지 확인
$ mongo localhost:10004/admin
MongoDB shell version: 2.6.2
connecting to: localhost:10004/admin
second:PRIMARY> use test
switched to db test
second:PRIMARY> db.test_collection.count()
61709
 
## number:0은 first에 있고, number:38291은  second에 분산되어 있다고 했다.
## 실제로 그런지 확인해 보자. 정상이군
second:PRIMARY> db.test_collection.find({number:0})
second:PRIMARY> db.test_collection.find({number:38291})
{ "_id" : ObjectId("53a93817c09ddce1f1cf8ec4"), "number" : 38291 }

테스트 결과

10만 개를 넣었을 때, 4:6비율로 분산되었고,

ReplicaSet으로 된 first 서버의 Primary서버를 강제 종료하더라도 Auto Failover가 이루어져, 문제없이 읽기와 쓰기 작업 모두 성공적으로 동작하였다.

first 서버군이 모두 종료되었을 때에는, 읽기와 쓰기작업에 요청된 샤드키값이 second 서버군에 저장되어 있거나 저장할 값이라면 오류가 없었지만, first 서버군에 저장된 데이터이거나 저장할 값이라면 오류가 발생하였다.