MongoDB in Action 12

김하영·2022년 3월 2일
0

12. 샤딩을 통한 시스템 확장

MongoDB의 샤딩은 데이터베이스를 작은 조각으로 분할하여 단일 머신이 모든 데이터를 저장하거나
전체 로드를 처리하지 않도록 하기 위해 고안된 것이다.

그뿐만 아니라 MongoDB의 샤딩은 애플리케이션에 투명한데,
이는 샤딩 클러스터를 쿼리하기 위한 인터페이스가 복제 세트 또는 단일 mongod 서버 인스턴스를 쿼리하기 위한 인터페이스와 완전히 동일하다는 것을 뜻한다.

12.1 샤딩 개관

12.1.1 샤딩이란 무엇인가?

  • 샤딩(sharding) : 대규모의 데이터 세트를 작고 관리하기 쉬운 조각으로 분할하는 과정
한대의 서버에 빅데이터를 저장하게 되면 I/O가 한대에서 일어난다.
서버를 여러 개를 두고 분산 저장한다면 I/O 가 여러 대에서 일어나기 때문에 효율이 좋아진다.

12.1.2 언제 샤딩을 사용하는가?

  1. 전체 작업 데이터를 물리적 Ram이 수용할 수 없을 때
  2. 쓰기 부하가 너무 커질 때

일반적으로 샤딩은 저장소(storage) 분산과 부하(load) 분산이라는 두 가지 주요한 목적을 가지고 있다.
샤딩의 모든 성능 문제를 해결하는 것은 아니며, 추가적인 복잡성과 오버헤드를 발생시키므로

왜 샤딩을 하는지 이해하는 것이 중요하다.

  1. 저장소 분산
    저장소의 용량을 주의 깊게 모니터링하면 애플리케이션이 늘어남에 따라 애플리케이션에 필요한 저장소가

하나의 노드 용량을 언제 초과하는지 명확하게 알 수 있다.
이 경우 더 많은 용량을 추가할 수 없는 경우 샤딩이 최선의 방법일 수 있다.

  1. 부하 분산
    쓰기 부하가 많이 요구된다면 데이터가 램의 크기에 도달하기 전에 샤딩을 할 수 있는데, 왜냐하면 원하는 쓰기 처리율을 얻기 위해 여러 대의 서버에 걸쳐서 부하를 분산시킬 필요가 있기 때문이다.

어느 정도의 여유 공간을 남겨두자!

자동적인 밸런싱을 위한 프로세스는 과부하된 샤드에서 데이터를 이동시켜야 하므로 샤딩 자체는 시스템에 부하를 가중시킨다. 과부하가 발생할 수 있는 상황이 아님에도 시스템에 이미 과부하가 걸렸을 경우 빈 샤드는 비어 있는 채로 남아있고, 과부화 상태의 샤드는 과부하가 걸린 상태로 남아 있으며, 시스템은 정지된다.

따라서, 미리 네트워크 사용, 디스크 사용 그리고 언제나 중요한 작업 데이터 대 사용 가능한 램의 비율을 정기적으로 분석한 결과를 모니터링 해야한다.

12.1.3 샤딩의 목적

  1. 데이터 분산을 통한 부하 분산
    데이터를 분산하여 순차적으로 저장한다면 한 대 이상에서 트래픽을 감당하기 때문에 부하를 분산하는 효과가 있다.

  2. 백업과 복구 전략
    미리 데이터를 분산하여 저장해둔다면 리스크로부터 보호받고 효과적인 시스템 운영이 가능해진다.

  3. 빠른 성능
    여러 대의 독립된 프로세스가 병렬로 작업을 동시에 수행하기 때문에 이상적으로 빠른 처리 성능 보장한다.

12.2 샤드 클러스터 구성 요소의 이해

샤딩이 가능하도록 하기 위해서는 여러 구성 요소가 함께 작동해야 한다.
모든 것이 함께 기능적으로 작동할 때 이것을 샤드 클러스터(shard cluster)라고 한다.

  1. 샤드 (Shard A / Shard B) : 애플리케이션 데이터의 저장소

애플리케이션 데이터를 분산하여 저장한다.
단일 mogod 서버이거나 애플리케이션 데이터의 파티션을 저장하는 레플리카셋(replica set)이다.
실제로 샤드는 애플리케이션 데이터가 샤드된 클러스터에 저장되는 유일한 장소이다.

샤드 클러스터에서는 오직 mongos 라우터 또는 시스템 관리자만 샤드에 직접 연결해야 한다.
또한 무조건 운영환경에서는 레플리카셋(replica set)으로 배포하야한다.

개별 사드에 연결은 가능하나, 해당 샤드에서 직접 연산을 실행하려 하면 클러스터의 전체 데이터 중 일부만 표시된다.

  1. Mongos 라우터 : 연산 라우터

클러스터 메타데이터를 캐시하고 이를 사용하여 올바른 샤드에 작업을 라우팅하거나 샤딩한다.
(샤드에 작업을 라우팅하는게 샤딩하는거 아닌가...?)

mongos 는 지속성이 없는 경량 프로세스다. 이러한 이유로 애플리케이션 서버와 동일한 시스템에 배포되며,
특정 샤드에 대한 요청에는 하나의 네트워크 홉(hop)만 필요하다. 즉, 애플리케이션을 로컬 mongos에 연결하고
mongos는 개별 샤드에 대한 연결을 관리한다.

  1. Config servers : 메타데이터의 저장소

클러스터에 대한 메타데이터를 영구적으로 저장하며, 여기에는 어떤 샤드가 어떤 데이터 하위 집합을 가지는지가 포함된다.

메타 데이터란?
글로벌 클러스터의 설정사항과 각 데이터베이스, 컬렉션, 각 범위의 데이터의 위치 그리고 샤드 간 데이터의 전송 내역을 가지고 있는 변동사항 로그
즉, 실제 데이터가 아니라 목차. (= 인덱싱)

12.3 샤드된 클러스터에서의 데이터 분산

MongoDB에서 데이터를 그룹화하고 구성하는 방법에 대해 알아보자.

MongoDB에는 도큐먼트, 청크, 컬렉션 및 데이터베이스 등 네 가지 단위(granularity) 수준이 있음을 알 수 있다.

  1. 도큐먼트
    MongoDB에서 가장 작은 데이터 단위.

  2. 청크
    피드의 값별로 클러스터된 도큐먼트 그룹.
    샤드 설정에만 존재하는 개념으로, 샤드 키(shared key)라는 필드 또는 필드 집합에 대한 값을 기반으로 하는 도큐먼트의 논리적 그룹이다.

  3. 컬렉션
    데이터베이스 내에 명명된 그룹화된 도큐먼트

  4. 데이터베이스
    도큐먼트 모음(컬렉션)을 포함하며, 시스템의 최상위 레벨 그룹이다.
    데이터베이스 이름과 컬렉션 이름의 조합은 시스템 전체에서 고유하며, 일반적으로 네임스페이라고 한다.

12.3.1 샤드된 클러스터에 데이터를 분산시킬 수 있는 방법

데이터베이스, 컬렉션, 청크, 도큐먼트 그룹 중 두 개에 있는 샤드 클러스에 분산될 수 있는 방법은 아래와 같다.

  1. 전체 데이터베이스의 수준에서 각 데이터베이스가 모든 컬렉션과 함께 자기 자신의 샤드에 위치한다.

  2. 컬렉션의 파티션 또는 청크 수준에서 컬렉션의 도큐먼트 자체가 분할되어 도큐먼트의 샤드 키라는 필드 또는 필드 집합의 값에 따라 여러 샤드에 분산된다.

12.3.2 샤드에 데이터베이스 분산 처리

샤드된 클러스터에 새 데이터베이스를 만들면 각 데이터베이스가 다른 샤드에 할당된다.
아무것도 하지 않으면 데이터베이스와 모든 컬렉션이 생성된 샤드에서 영원히 머물게 된다.
데이터 베이스 자체는 샤딩할 필요조차 없고 권장하지는 않는다.

클라이언트가 대략 동일한 양의 데이터를 사용하면 클러스터 전체에 데이터 베이스가 분산되므로
이때는 샤드에 데이터베이스 분산처리가 유용하다.

12.3.3 컬렉션 내에서 샤딩하기

자동 샤딩 : MongoDB 자체가 모든 파티셔닝 결정을 내리는 샤딩의 형태로, 컬렉션 내에서 샤딩한다.

개별 컬렉션의 파티셔닝을 허용하기 위해서는 샤드 키라는 필드 세트를 기반으로 도큐먼트의 논리적인 그룹인 청크의 개념을 정의한다.

청크는 샤드 키의 범위를 나타낸다.
MongoDB는 자신이 속한 청크를 결정하기 위해 도큐먼트를 볼 때, 먼저 샤드 키의 값을 추출한 다음 주어진 샤드 키 값이 샤드 키 범위에 들어 있는 청크를 찾는다.

12.4 샘플 샤드 클러스터 구축하기

샤드된 클러스터를 구축하는 전 과정은 3단계로 구성된다.

  1. mongod 및 mongos 서버 시작
    클러스터를 구성하는 모든 mongod 및 mongos 프로세스를 생성하는 것이다.
    클러스터에서는 9개의 mongod 서버와 1개의 mongos 를 생성한다.

  2. 클러스터 구성
    replica set 이 초기화되고 샤드가 클러스터에 추가되도록 구성을 업데이트하는 것이다.
    이후에 노드는 모두 서로 통신할 수 있다.

  3. 샤딩 컬렉션
    컬렉션을 여러 샤드에 분산시킬 수 있도록 컬렉션을 분할하는 것이다.

12.5 샤딩 클러스터 질의 및 인덱싱

12.5.1 쿼리 라우팅

  1. 타깃 쿼리

  1. 글로벌 쿼리

12.5.2 샤드 클러스터에서 인덱싱하기

인덱싱은 성능을 최적화하는 중요한 부분이다.

샤드된 클러스터에만 적용되는 인덱싱에 대해 염두에 두어야 할 핵심 사항은 다음과 같다.

  1. 각 샤드는 자신만의 인덱스를 가진다.
    샤드 컬렉션에 대해 인덱스를 선언하면 각 샤드는 자신이 담당하고 있는 부분의 컬렉션에 대해 별도의 인덱스를 생성한다.

  2. 각 샤드에 대한 샤드 컬렉션은 같은 인덱스가 있어야 한다.
    그렇게 되지 않으면 쿼리 언어 성능이 일관적이지 못한다.

  3. 샤드 컬렉션은 _id 필드와 샤드 키에 대해서만 고유 인덱스를 허용한다.
    다른 필드에 대한 고유 인덱스는 금지된다.

12.6 샤드 키 선택

잘못된 샤드 키의 함정을 이해하는 가장 좋은 방법은 단계별로 좋은 것을 찾는 과정을 거치면서 그 진행되는 과정에서 고려할 각 샤드 키를 깊이 분석하는 것이다.

샤드 키를 선택하는 과정을 거칠 때, 세 가지 주요 함정을 확인할 수 있다.

  1. 핫스팟(Hotspots)
    일부 샤드 키는 모든 읽기 또는 쓰기가 단일 샤드에 있는 단일 청크로 향하는 상황을 만든다.
    이로 인해 하나의 샤드는 완전히 주체할 수 없는 상황이 되고, 나머지는 유휴 상태가 된다.
    (유휴 상태..? : 어떠한 프로그램에 의해서도 사용되지 않는 상태)

  2. 분할할 수 없는 청크
    너무 조잡한 샤드 키는 동일한 샤드 키를 가진 도큐먼트를 다수 발생시킬 수 있는 상황을 초래할 수 있다.

  3. 낮은 수준의 타기팅
    쓰기가 클러스터에 완벽하게 분산되더라도 샤드 키가 쿼리와 관계가 없으면 쿼리 성능이 저하된다.

12.6.4 이상적인 샤드 키

  1. 읽는 방법
  2. 쓰기가 얼마나 잘 분산되는지
  3. 청크를 얼마나 효율적으로 분할하고 마이그레이션 할 수 있는지

이 세 가지 모두에 적합한 샤드 키를 고를 수 있을까?
예상대로 해답은 모든 이점을 제공하는 복합 샤드 키를 사용하는 것이다.
예) {username:1, _id:1}

(샤드 키 설계가 제일 중요하군..!)

참고

https://www.slideshare.net/sejoonlim/mongo-db-sharding-16741367

profile
Back-end Developer

0개의 댓글