정환타 개발노트

MongoDB Sharding(샤딩) 본문

Dev-Database/NoSQL

MongoDB Sharding(샤딩)

JungHwanTa 2020. 2. 12. 18:55

Sharding

MongoDB의 샤딩(Sharding)을 알아보기 전에 먼저, 샤딩에 대한 개념을 알아보자.

 

샤딩은 데이터를 여러 서버에 분산해서 저장하고 처리할 수 있는 기술을 말한다. 복제(Replication)와의 차이점이 있다면, 복제는 고가용성을 위한 솔루션이고 샤딩은 분산 처리를 위한 솔루션이라는 것이다.

(몽고디비에서는 고가용성과 대용량 분산 처리를 위해 복제와 샤딩을 모두 적용한다.)

 

일반적으로 부산 처리를 할수 있는 방법에는 vertical scaling 과 horizontal scaling 두가지가 있다.

 

먼저, Vertical scaling은 수직 확장의 개념으로 이해할 수 있는데 단일 서버를 확장하고자 할 때 사용한다. 예를 들어 고성능의 CPU를 사용하거나 RAM을 추가하거나 저장공간을 확장하는 개념으로 볼 수 있다.

 

다음으로, Horizontal scaling은 수평 확장의 개념으로 이해할 수 있는데 쉽게 말해 데이터를 두 개 이상의 테이블에 나누어 저장하는 방식을 말한다. MongoDB에서는 Sharding을 통해서 horizontal scaling을 지원한다.

 

Sharded Cluster

샤딩에 대해 자세히 알아보기 전에 먼저 Sharded Cluster에 대한 이해가 필요하다.

 

먼저 Sharded Cluster는 다음과 같은 구성요소가 있다.

- Shard : 샤드 데이터(sharded data)의 집합, 샤드는 Replica set이 될 수 있다.

- Mongos : 몽고스는 쿼리 라우터와 같은 역할을 하는데, 애플리케이션과 샤드 클러스터간의 인터페이스를 제공한다.

- Config servers : 설정 서버에서는 클러스터의 메타 데이터와 설정들을 저장한다. 

 

따라서 샤드 클러스터는 다음과 같은 구조로 구성된다.

 

 

몽고디비는 콜렉션 단에서 데이터를 샤딩해서 클러스터 샤드에 콜렉션 데이터를 분배한다.

 

Shard Keys

몽고디비는 샤드 키(Shard keys)를 이용하여 컬렉션의 document를 샤드에 배포한다. 

별도로 지정하지 않는다면 샤드 키는 Object_id(_id)가 되며, 해당 컬렉션의 모든 document에 존재하는 field index라면 샤드 키로 지정할 수 있다.

 

추가적으로 샤드 키에는 몇가지 제약 조건이 있다.

1. 샤드키는 512byte 를 넘을 수 없다.

2. 샤딩한 컬렉션의 샤드 키는 변경할 수 없다.

3. 샤드 키로 지정된 필드의 value는 변경할 수 없다.

Chuncks

몽고디비는 샤딩 된 데이터를 분할한다. 각 분할 된 조각들을 여러개의 샤드 서버에 분산해서 저장하는데, 이 데이터 조각을 Chunks라고 한다. 이 chunk는 각 샤드서버에 균등하게 저장되어야 좋은 성능을 낼 수 있는데, 균등하기 저장하기 위해서 chunks를 split 하고 migration 하는 과정을 거친다.

 

다음으로는 샤드 키를 이용하여 샤드를 분할한 그림이다.

 

 

그림에서 보이듯, x를 샤드 키로 설정하여 4개의 Chunks로 나누고, 각 Chunks마다 범위(Ranged Sharding)를 가진다. 

 

샤드 키를 지정하는 것은 샤드의 Chunks들의 생성과 연관되며 데이터 활용에 영향을 준다. 즉, 샤드 키가 샤드 클러스터에서 작업에 효율성과 성능에 직결되어 있다는 뜻이다.

 

위의 그림에서 샤드 키를 잘 적용한 상태이다. 반대로 비효율 적인 샤드 키를 선택한 경우를 보자.

 

위에서는 샤드 키로 지정한 필드의 값이 중복해서 들어온다. 따라서 샤드를 분할하여 사용한다고 하더라도, 같은 샤드로만 요청이 들어오기 때문에 샤딩을 활용한 이점을 활용하기가 어렵다. 

따라서 샤드 키를 적절한 필드로 지정하는 것은 위에서 말한 작업 효율성과 성능과 직결되기에 중요한 문제라고 할 수 있다.

 

Hashed Sharding

Hashed Sharding은 hashed index를 이용해서 샤드 클러스에 데이터를 분배하는 샤딩을 말한다.

이 Hashed 샤딩을 써야하는 경우는, 만일 1,2,3,4,5와 같은 단조로은 필드 값을 키로 써야한다고 가정했을때, 3개의 샤드 서버를 나누게 되면 대략 [1.2], [3,4], [5]의 형태로 구성될 것이다. 만약 여기서 추가적인 값(6,7,8,9, ....)들이 들어온다면 이후의 값들은 모두 마지막 샤드 서버로 들어가게 될 것이다. 이런 경우에 Hashed 샤딩을 통해서 문제를 해결할 수 있다.

 

 

Hashed indexes를 통해서 샤드 클러스터를 구성하는 방법은 다음과 같다.

sh.enableSharding("<database>")
sh.shardCollection("<database>,<collection>", {<shard key>: "hashed"}}

 

Zones

샤드 클러스터에서는 샤드 키를 이용하여 샤드 데이터들의 영역(Zones)을 만들 수 있다. 이 각 샤드들은 하나 이상의 양역을 가질 수 있고 각 영역은 하나 이상의 샤드 키값 범위를 포함한다. 

 

영역(zone)의 범위를 정의 할 때 샤드 키에 포함된 범위를 사용해야 하며, 복합 샤드 키를 사용하기 위해서는 샤드 키의 접두사가 포함되어야 한다.

 

샤드 존을 설정하는 방법은 다음과 같다.

 

1. 샤드를 영역에 추가

sh.addShardTag(<shard name>, <zone name>)
sh.addShardToZone("shard0000", "NYC")
sh.addShardToZone("shard0001", "NYC")
sh.addShardToZone("shard0002", "SFO")
sh.addShardToZone("shard0002", "NRT")

2. 영역의 범위 생성

sh.updateZoneKeyRange("records.users", { zipcode: "10001" }, { zipcode: "10281" }, "NYC")
sh.updateZoneKeyRange("records.users", { zipcode: "11201" }, { zipcode: "11240" }, "NYC")
sh.updateZoneKeyRange("records.users", { zipcode: "94102" }, { zipcode: "94135" }, "SFO")

범위 삭제는 다음과 같다.

sh.removeRangeFromZone("records.user", {zipcode: "10001"}, {zipcode: "10281"})

3. 생성된 영역 확인

use config
db.shards.find({ tags: "NYC" })

Sharded Cluster Balancer

샤드 밸런서는 모든 샤드 컬렉션에 Chunck를 균등하게 재분배 하는 역할을 한다. 위에서 효율성을 위해 Chuncks를 migration하고 split한다고 했었는데, 이 샤드 밸런서가 그 역할을 한다.

 

Chunks 분배를 위해서 밸런서는 Chunks가 많은 샤드에서 Chunks 수가 적은 샤드로 마이그레이션 하는데, 이 작업을 모든 샤드에 Chunks가 고르게 분포 될 때까지 수행한다. 기본적으로 샤드 밸런서는 활성화 상태로 유지된다.

 

샤드 밸런서를 활성화하고 비활성화 하는 것도 가능하며, 추가적으로 샤드 밸런서를 스케쥴을 통해 시작 시간과 종료 시간을 지정 할 수 있다. 설정에서 'balancer'의 acitveWindow 필드를 통해서 스케쥴을 지정할 수 있다.

db.settings.update(
   { _id: "balancer" },
   { $set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } } },
   { upsert: true }
)

또한 단일 컬렉션에 대한 밸런스 설정도 가능하다. 아래에서는 student.grades의 샤드 밸런싱을 설정한다.

sh.enableBalancing("students.grades")

밸런서를 사용하지 않고 Chunck를 migration하는 것도 가능하다.

db.adminCommand( { moveChunk : "myapp.users",
                   find : {username : "smith"},
                   to : "mongodb-shard3.example.net" } )

 

Comments