[MongoDB] Sharding

2020. 12. 18. 02:34Database/MongoDB

1. Shard Cluster의 쿼리 수행 절차

  • 사용자 쿼리가 참조하는 컬렉션의 Chunk 메타 정보를 Config Server로 부터 가져와 라우터의 메모리에 캐시한다.
  • 사용자 쿼리의 조건에서 Sharding Key 조건을 찾는다.

    - 쿼리 조건에 Sharding Key가 존재할 경우 해당 Sharding Key가 포함된 Chunk 정보를 라우터의 캐시에서 검색하여 해당 Shard 서버로만 사용자 쿼리를 요청한다.

    - 쿼리 조건에 Sharding Key가 없을 경우 모든 Shard 서버로 사용자의 쿼리를 요청한다.

  • 쿼리를 전송한 대상 Shard 서버로부터 쿼리 결과가 도착하면 결과를 병합하여 사용자에게 결과를 반환한다.

 

동작 과정

 

 

 

2. Sharding

1) Sharding

Sharding은 데이터를 여러 서버에 분산해서 저장하고 처리할 수 있는 기술을 말한다. 복제의 경우 고가용성을 위한 솔루션이라면, Sharding은 분산 처리를 위한 솔루션이다. 물론 MongoDB에서는 고가용성과 대용량 분산 처리를 위해 복제와 샤딩을 모두 적용한다.

 

Vertical Scaling은 분산 처리 방법 중 하나로, (수직 확장의 개념) 단일 서버를 확장하고자 할 때 사용하는 방법이다. 고성능의 CPU를 사용하거나 RAM을 추가하여 저장공간을 확장하는 개념이라고 생각하면 쉽다.

 

Horizontal Scaling은 수평 확장의 개념으로 데이터를 두 개 이상의 테이블에 나누어 저장하는 방법을 뜻한다. MongoDB에서는 Sharding을 통해 Horizontal Scaling을 지원한다.

2) Sharded Cluster

Sharded Cluster에는 3가지 구성 요소가 있다.

  • Shard 란 Sharded Data의 집합으로 Shard는 Replica Set이 될 수 있다.
  • Mongos 란 쿼리 라우터와 같은 역할로 애플리케이션과 Shard Cluster간의 인터페이스를 제공한다.
  • Config Servers 란 설정 서버에서 클러스터의 메타 데이터와 설정들을 저장한다.

 

MongoDB는 컬렉션 단에서 데이터를 Sharding하여 Cluster Shard에 컬렉션 데이터를 분배한다.

Sharded Cluster 구성 요소

3) Shard Keys

MongoDB는 Shard Key를 이용하여 컬렉션의 Document를 Shard에 배포한다. 별도로 지정하지 않을 경우, Shard Key는 Object_id(_id)가 되며, 해당 컬렉션의 모든 Document에 존재하는 필드 인덱스라면 Shard Key로 지정할 수 있다.

 

Shard Key에는 몇 가지의 제약이 있다.

  • Shard Key는 512 Byte를 넘어서는 안된다.
  • Sharding한 컬렉션의 Shard Key는 변경할 수 없다.
  • Shard Key로 지정된 필드의 값은 변경할 수 없다.

4) Chunks

MongoDB는 Sharding된 데이터를 분할한다. 각 분할 된 조각들을 여러 개의 Shard 서버에 분산해서 저장하는데, 이 데이터 조각을 Chunks라고 한다. Chunks는 각 Shard 서버에 균등하게 저장되어야 좋은 성능을 낼 수 있는데, 균등하게 저장하기 위해서 Chunks를 Split하고 Migration하는 과정을 거친다.

 

하단의 이미지에서 확인할 수 있듯, x를 Shard Key로 설정하여 4개의 Chunks로 나누고, 각 Chunks 마다 범위를 가진다. Shard Key를 지정하는 것은 Shard의 Chunks들의 생성과 연관되며 데이터 활용에 영향을 준다. 즉, Shard Key가 Shard Cluster에서 작업에 효율성과 성능에 직결되어 있다.

Shard Key를 이용한 Shard 분할

작업의 효율성과 성능에 직결되는 중요한 문제라고 하는 이유는, 하단의 이미지처럼 Shard Key를 지정할 경우 필드의 값이 중복해서 들어오기 때문이다. 즉, Shard를 분할하더라도 같은 Shard로만 요청이 들어오기 때문에 Sharding을 활용한 이점이 떨어진다.

Shard 분할

 

 

 

3. Hashed Sharding

Hashed Sharding은 Hashed Index를 이용하여 Shard Cluster에 데이터를 분배하는 Sharding을 말한다. Hashed Sharding을 사용하는 이유는 예시를 통해 쉽게 이해할 수 있다.

 

예를 들어 1,2,3,4,5와 같은 단조로운 필드 값을 키로 사용한다고 가정했을 때, 3개의 Shard 서버를 나누게 되면 대략 [1,2], [3,4], [5]의 형태로 구성된다. 만약 여기서 추가적인 값 (6,7,8,9,...)이 들어온다면 이 후의 값들은 모드 마지막 Shard 서버로 들어오게 된다.

Hashed Sharding 사용 이유

Hashed Index를 통해서 Shard Cluster를 구성하는 방법은 다음과 같다.

sh.enableSharding("<데이터베이스>")
sh.shardCollection("<데이터베이스>,<컬렉션>", { <Shard Key>: "hashed" } } )

Hashed Sharding 적용

※ 그 외에도 Ranged Sharding이 있다.

 

 

 

4. Zones

Shard Cluster에서는 Shard Key를 이용하여 Shard Data들의 영역을 만들 수 있다. 이 각 Shard들은 하나 이상의 영역을 가질 수 있고 각 영역은 하나 이상의 Shard 키-값 범위를 포함한다.

 

영역의 범위를 지정할 때 Shard Key에 포함된 범위를 사용해야 하며, 복합 Shard Key를 사용하기 위해서는 Shard Key의 접두사가 포함되어야 한다.

Zones

Shard Zones를 설정하는 방법은 다음과 같다.

// Shard를 영역에 추가
sh.addShardTag( <Shard명>, <Zone명> )
sh.addShardToZone( "shard0000", "NYC" )
sh.addShardToZone( "shard0001", "NYC" )
sh.addShardToZone( "shard0002", "SFO" )
sh.addShardToZone( "shard0003", "NRT" )

// 영역의 범위 생성
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.users", { zipcode: "10001" }, { zipcode: "10281" } )

// 생성된 영역 확인
use config
db.shards.find( { tags: "NYC" } )

 

 

 

5. Sharded Cluster Balancer

Shard Balancer는 모든 Shard 컬렉션에 Chunks를 균등하게 재분배하는 역할(Chunks를 Split하고 Migration하는 역할)을 수행한다. Chunks 분배를 위해서 Balancer는 Chunks가 많은 Shard에서 Chunks 수가 적은 Shard로 Migration을 하는데, 이작업을 모든 Shard에 Chunks가 고르게 분포 될 때까지 수행한다. 기본적으로 Shard Balancer는 활성화 상태로 유지된다.

Sharded Cluster Balancer

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

db.settings.update(
  { _id: "balancer" },
  { $set: {activeWindow: { start: "<시작 시간>", stop: "<종료 시간>" } } },
  { upsert: true }
)

단일 컬렉션에 대한 Balancer 설정도 가능하다.

sh.enableBalancing("students.grades")

Balancer를 사용하지 않고 Chunks를 Migration하는 것도 가능하다.

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

[참고] junghwanta.tistory.com/41?category=857330

728x90

'Database > MongoDB' 카테고리의 다른 글

[MongoDB] Aggregation Pipeline  (0) 2020.12.18
[MongoDB] Sharding (Shard, Config Server, Mongos)  (0) 2020.12.18
[MongoDB] Database 참조  (0) 2020.12.18
[MongoDB] Model 활용  (0) 2020.12.18