11-19 08:26
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[MongoDB] Sharding / Product Configuration 본문

Data Science/MongoDB

[MongoDB] Sharding / Product Configuration

cinema4dr12 2014. 4. 23. 23:04

by Geol Choi | 

지난 글에서는 개발단계 수준에서의 데이터 샤딩에 대하여 알아보았다. 실제 어플리케이션의 서비스 단계에서는 보다 안정성이 요구되기 때문에 이번 글에서는 이에 필요한 설정에 대해 알아보도록 하겠다.

데이터 운용의 안정성을 위해서는 다음과 같은 항목들이 요구된다:

  • 다중의 config server들

  • 다중의 mongos server들

  • 각 샤드에 대한 리플리카(Replica) 구성


샤딩에 대한 내용을 다루면서 익숙치 않은 많은 용어들이 한꺼번에 등장하여 혼란스러울 수 있으므로 다음 그림을 통해 전체적인 용어와 이들의 관계에 대하여 이해하도록 한다.

[그림 1.] App Server, Router(Routing Server), Config Server, Shard(Replica Set)에 대한 관계도. 샤드 클러스터 구성의 예.


[그림 1.]의 샤드 클러스터 예를 보면, 이는 3개의 Config Server들과 2개 이상의 mongos Router(어플리케이션 서버) 및 2개 이상의 샤드(Replica Set)로 구성되어 있음을 알 수 있다.

지난 글에서도 언급하였었지만 각각의 역할에 대해 간단히 언급하면 다음과 같다:

  • Shard(Replica Set)는 데이터를 저장하는 저장소이다. 프로덕션 레벨에서의 샤드 클러스터에 있어 높은 가용성과 데이터 일치성을 위해 각 샤드는 리플리카 세트가 된다. 

  • Query Router 또는 mongos 인스턴스는 클라이언트 어플리케이션에 대한 인터페이스 역할을 하며 해당 샤드(들)에게 연산을 수행하도록 한다. 즉, 클라이언트 어플리케이션으로부터 요청을 받아 해당 샤드(들)에게 연산을 수행하도록 명령하고 해당 샤드(들)에게로부터 결과를 받아 클라이언트 어플리케이션에 전달하는 역할을 한다. 클라이언트 요청에 대한 부담을 분산하기 위해 샤드 클러스터는 여러 개의 Query Router를 가질 수 있으며, 서비스를 위한 대부분의 경우 많은 Query Router를 구성하도록 한다.

  • Config Server는 클러스터의 메타데이터를 저장한다. 이 데이터는 클러스터의 데이터 세트를 샤드들에 맵핑하는(연관짓는) 것에 대한 것이다. Query Router는 이 메타데이터를 이용하여 특정 연산에 해당하는 샤드를 어떤 것인지 파악한다. 실제 서비스를 하는 프로덕션 레벨에서는 정확히 3개의 Config Server를 갖는다.


이제 본격적으로 예제를 통해 프로덕션 레벨의 샤드 클러스터를 구성해 보자. 사용된 머쉰의 대수는 2대이며, 이해를 돕기위해 머쉰 및 서버 구성은 다음 표와 같다:


[표 1.] 샤드 클러스터 구성 정보.

Config Servers


 Machine

 --dbpath

 --port

 config 1

 M1 (192.168.10.103)

 .../config1

 20001

 config 2

 M1 (192.168.10.103)

 .../config2

 20002

 config 3

 M1 (192.168.10.103)

 .../config3

 20003

Routing Servers


 Machine

 --configdb

 --port

 routing 1

 M1 (192.168.10.103)

 192.168.10.103:20001

 30001

 routing 2

 M2 (192.168.10.101)

 192.168.10.103:20002

 30002

Shards

  Machine --dbpath --port
 shard 1 M1 (192.168.10.103) .../shard1 40001
 shard 2

 M2 (192.168.10.101)

 .../shard2 40002

 shard 3

 M2 (192.168.10.101)

 .../shard3 40003
 shard 4 M1 (192.168.10.103) .../shard4 40004

mongos Instance

 

 Machine

 --host

 --port

 mongos 1 M2 (192.168.10.101) 192.168.10.103 30001
 mongos 2 M1 (192.168.10.103)

 192.168.10.101

 30002


샤드 클러스터 구성 정보를 표로 정리해 보았는데, 꽤 복잡해 보일 것이다. 샤드 클러스터 구성에 대한 이해를 돕기 위해 오히려 구성을 좀 더 복잡하게 하였다. 총 2대의 머쉰을 사용하였는데 첫번째 머쉰 M1의 IP주소는 192.168.10.103이며, 두번째 머쉰 M2의 IP주소는 192.168.10.101이다. 각자의 머쉰에 따라 IP주소는 다르니 유의하기 바란다.

표에서 "Machine"이라고 표현한 부분은 각 구성요소의 서버가 실행되는 머쉰을 의미한다. 위의 표를 바탕으로 전체 샤드 클러스터 구성도를 작성하면 다음과 같다:


   [그림 2.] 예제에서 사용될 샤드 클러스터 구성도.


다중의 Config Server들

[그림 2.]에서 보는 바와 같이 Config Server들 M1에서만 설정하였다.

Config Server 1에 대한 mongod 인스턴스 실행은 다음과 같다:

$ mongod --configsvr --dbpath /[YOUR_DB_PATH]/config1 --port 20001


Config Server 2에 대한 mongod 인스턴스 실행은 다음과 같다:

$ mongod --configsvr --dbpath /[YOUR_DB_PATH]/config2 --port 20002


Config Server 3에 대한 mongod 인스턴스 실행은 다음과 같다:

$ mongod --configsvr --dbpath /[YOUR_DB_PATH]/config3 --port 20003


다중의 Routing Server들

mongos 인스턴스 또는 Routing Server는 원하는 만큼 설정이 가능하나 클라이언트 어플리케이션 서버의 수만큼 설정하는 것이 일반적이다.

[표 1.]에서 보는 바와 같이 Routing Server 1은 M1에서 실행되며, Routing Server 2는 M2에서 실행된다.

Routing Server 1에 대한 mongos 인스턴스 실행은 다음과 같다:

$ mongos --configdb 192.168.10.103:20001 --port 30001


Routing Server 2에 대한 mongos 인스턴스 실행은 다음과 같다:

$ mongos --configdb 192.168.10.103:20002 --port 30002


Shard 설정

[표 1.]에서 보는 바와 같이 Shard 1과 Shard 4는 M1에서 실행되며, Shard 2와 Shard 3는 M2에서 실행된다.

Shard 1에 대한 mongod 인스턴스 실행은 다음과 같다 (M1에서 실행):

$ mongod --dbpath /[YOUR_DB_PATH]/shard1 --port 40001


Shard 2에 대한 mongod 인스턴스 실행은 다음과 같다 (M2에서 실행):

$ mongod --dbpath /[YOUR_DB_PATH]/shard2 --port 40002


Shard 3에 대한 mongod 인스턴스 실행은 다음과 같다 (M2에서 실행):

$ mongod --dbpath /[YOUR_DB_PATH]/shard3 --port 40003


Shard 4에 대한 mongod 인스턴스 실행은 다음과 같다 (M1에서 실행):

$ mongod --dbpath /[YOUR_DB_PATH]/shard4 --port 40004


mongos 인스턴스 실행

[표 1.]과 같이 mongos 1은 M2에서, mongos 2는 M1에서 실행한다.

mongos 1에 대한 실행 명령은 다음과 같다 (M2에서 실행):

$ mongo --host 192.168.10.103 --port 30001


mongos 2에 대한 실행 명령은 다음과 같다 (M1에서 실행):

$ mongo --host 192.168.10.101 --port 30002


mongos 1과 mongos 2에 대해 mongos 인스턴스 실행 시 디폴트 db는 test이므로 다음과 같이 admin db로 이동한다 (각각의 mongos 명령 쉘에서 실행해야 한다):

mongos> use admin
switched to db admin


앞서 언급한 바와 같이 mongos 인스턴스의 개수는 클라이언트 어플리케이션의 개수와 동일하게 설정한다고 하였다. 즉, 본 예제의 경우 2개의 mongos 인스턴스를 실행한다는 것은 클라이언트 어플리케이션 또한 2개인 것을 가정하고 있다.


Shard 추가

이제 모든 서버 인스턴스 실행은 마무리 되었다. 남은 것은 샤드를 추가하는 것이다. 총 4개의 샤드 서버가 실행 중이며 현재 실행되고 있는 mongos 명령 쉘에서 "addShard" 명령을 통해 이들을 추가한다.

M1에서 실행되고 있는 mongos 2(클라이언트 어플리케이션 #2)에 shard 1을 추가한다:

mongos> db.runCommand({addShard: "192.168.10.103:40001"})
{ "shardAdded" : "shard0000", "ok" : 1 }


M1에서 실행되고 있는 mongos 2(클라이언트 어플리케이션 #2)에 shard 2를 추가한다:

mongos> db.runCommand({addShard: "192.168.10.101:40002"})
{ "shardAdded" : "shard0001", "ok" : 1 }


M2에서 실행되고 있는 mongos 1(클라이언트 어플리케이션 #1)에 shard 3를 추가한다:

mongos> db.runCommand({addShard: "192.168.10.101:40003"})
{ "shardAdded" : "shard0001", "ok" : 1 }


M2에서 실행되고 있는 mongos 1(클라이언트 어플리케이션 #1)에 shard 4를 추가한다:

mongos> db.runCommand({addShard: "192.168.10.103:40004"})
{ "shardAdded" : "shard0001", "ok" : 1 }


데이터 샤딩

이제 길고 길었던 여정이 어느덧 마무리 되어 가는 듯 하다. 마지막으로 데이터 샤딩만 남았다.

우선 클라이언트 어플리케이션 #1(mongos 1)에 대한 데이터를 입력한다. mongos 1의 명령 쉘에서 jobs라는 이름의 db로 이동한다:

mongos> use jobs
switched to db jobs


그리고 이 db에 다음과 같이 데이터가 존재한다고 하자:

mongos> db.tasks.insert({todo : "shopping", status : "READY", priority : "4", _id: 1})
mongos> db.tasks.insert({todo : "studying Mongo DB", status : "READY", priority : "1", _id: 2})
mongos> db.tasks.insert({todo : "reporting the current job", status : "DONE", priority : "8", _id: 3})
mongos> db.tasks.insert({todo : "cleaning my room", status : "READY", priority : "3", _id: 4})
mongos> db.tasks.insert({todo : "meeting friends", status : "DONE", priority : "7", _id: 5})
mongos> db.tasks.insert({todo : "depositing money", status : "RUNNING", priority : "6", _id: 6})
mongos> db.tasks.insert({todo : "take a walk", status : "RUNNING", priority : "5", _id: 7})
mongos> db.tasks.insert({todo : "sending an email", status : "READY", priority : "2", _id: 8})


입력된 데이터를 살펴보면 다음과 같다:

mongos> db.tasks.find().pretty()
{ "_id" : 1, "todo" : "shopping", "status" : "READY", "priority" : "4" }
{
	"_id" : 2,
	"todo" : "studying Mongo DB",
	"status" : "READY",
	"priority" : "1"
}
{
	"_id" : 3,
	"todo" : "reporting the current job",
	"status" : "DONE",
	"priority" : "8"
}
{
	"_id" : 4,
	"todo" : "cleaning my room",
	"status" : "READY",
	"priority" : "3"
}
{
	"_id" : 5,
	"todo" : "meeting friends",
	"status" : "DONE",
	"priority" : "7"
}
{
	"_id" : 6,
	"todo" : "depositing money",
	"status" : "RUNNING",
	"priority" : "6"
}
{
	"_id" : 7,
	"todo" : "take a walk",
	"status" : "RUNNING",
	"priority" : "5"
}
{
	"_id" : 8,
	"todo" : "sending an email",
	"status" : "READY",
	"priority" : "2"
}


샤딩을 활성화하기 위해 다시 admin db로 이동한다:

mongos> use admin
switched to db admin


enableSharding 명령을 입력하여 jobs db에 대한 데이터를 샤딩한다:

mongos> db.runCommand({enableSharding: "jobs"})
{ "ok" : 1 }


이번에는 클라이언트 어플리케이션 #2(mongos 2)에 대한 데이터를 샤딩한다. mongos 1에 대한 내용과 방식은 동일하며 db 이름과 데이터만 다를 뿐이다. mongos 2의 명령 쉘에서 users라는 이름의 db로 이동한다:

mongos> use users
switched to db users


이 db에 다음과 같이 데이터가 존재한다고 하자:

mongos> db.member.insert({user: "cinema4d", pwd: "1234", email: "aaa@gmail.com"})
mongos> db.member.insert({user: "raspberry01", pwd: "asdf", email: "bbb@gmail.com"})
mongos> db.member.insert({user: "ozerodie", pwd: "asdf", email: "ccc@gmail.com"})
mongos> db.member.insert({user: "nicesubi", pwd: "asdf", email: "ddd@gmail.com"})


입력된 데이터를 살펴보면 다음과 같다:

mongos> db.member.find().pretty()
{
	"_id" : ObjectId("535920a5e1679452b81e1b83"),
	"user" : "cinema4d",
	"pwd" : "1234",
	"email" : "aaa@gmail.com"
}
{
	"_id" : ObjectId("535920a6e1679452b81e1b84"),
	"user" : "raspberry01",
	"pwd" : "asdf",
	"email" : "bbb@gmail.com"
}
{
	"_id" : ObjectId("535920a6e1679452b81e1b85"),
	"user" : "ozerodie",
	"pwd" : "asdf",
	"email" : "ccc@gmail.com"
}
{
	"_id" : ObjectId("535920a7e1679452b81e1b86"),
	"user" : "nicesubi",
	"pwd" : "asdf",
	"email" : "ddd@gmail.com"
}


샤딩을 활성화하기 위해 다시 admin db로 이동한다:

mongos> use admin
switched to db admin


enableSharding 명령을 입력하여 users db에 대한 데이터를 샤딩한다:

mongos> db.runCommand({enableSharding: "users"})
{ "ok" : 1 }


이번 예제는 샤딩을 연습하기 위해 꽤 복잡한 샤드 클러스터를 구성하여 보았다. 결국 클라이언트 어플리케이션과의 연계성을 포함하여 전체 구성을 그림으로 표현하면 다음과 같다.


   [그림 3.] 예제에서 사용된 샤드 클러스터와 클라이언트 어플리케이션과의 관계도.


Comments