사전 샤드
개념

샤드

gabury1

샤드는 전체 데이터를 쪼갠 조각 하나입니다. 조각마다 맡은 몫이 다릅니다. 조각들을 서로 다른 서버에 나눠 두면 한 대가 감당하던 양을 여러 대가 나눠 집니다.

상세

이삿짐을 상자 여럿에 나눠 담습니다. 상자를 아무리 잘게 나눠도 한 사람이 전부 지면 그 사람 어깨가 견디는 만큼이 한 번에 옮기는 전부입니다. 여러 사람이 한 상자씩 맡아 들 때 옮기는 짐이 사람 수를 따라 늘어납니다.

샤드는 데이터를 건수 단위로 나눈 조각 하나입니다. 열을 잘라 나누는 것이 아닙니다. 레코드나 문서를 줄 단위로 갈라 이쪽 조각과 저쪽 조각에 나눠 담습니다. 이렇게 나누는 것을 수평 분할이라고 부릅니다.

조각에는 두 가지 계약이 붙습니다. 첫째는 겹치지 않는다는 것입니다. 한 건은 한 조각에만 있고, 조각들을 다 합치면 전체가 됩니다. 둘째는 자족적이라는 것입니다. 조각 하나는 자기가 맡은 부분집합을 스스로 담고, 그 부분집합에 대한 읽기와 쓰기를 자기 안에서 끝낼 수 있습니다.

어느 조각에 들어갈지는 값에서 정해집니다. 나누는 기준이 되는 값을 샤드 키라고 부릅니다. 그리고 그 값을 조각 하나에 대응시키는 규칙이 따로 있습니다. 규칙이 있으니 찾는 쪽도 전부를 뒤지지 않습니다. 키에 규칙을 걸어 어느 조각으로 갈지 먼저 정하고 그 조각에만 묻습니다. 이 대응을 라우팅이라고 부릅니다.

flowchart TD
    K["찾는 값 · 샤드 키"] --> R["대응 규칙"]
    R --> S1["샤드 1"]
    R --> S2["샤드 2"]
    R --> S3["샤드 3"]

조각을 나누는 것 자체는 한 서버 안에서도 됩니다. 샤드라는 말이 붙는 자리는 그 조각들을 서로 다른 서버에 흩어 놓은 자리입니다. 그래야 저장 용량과 처리량이 서버 수를 따라 늘어납니다. 조각을 이고 있는 서버 하나하나를 노드라고 부르고, 그 노드들을 묶은 것을 클러스터라고 부릅니다.

그래서 이 이름은 데이터 조각을 가리키기도 하고 그 조각을 맡은 서버 쪽을 가리키기도 합니다. 읽는 문서마다 강세가 다를 뿐 가리키는 것은 하나입니다. 전체 데이터의 한 부분집합을 맡는 단위입니다.

배경

데이터가 한 서버에 다 들어가지 않는 자리가 옵니다. 디스크가 먼저 차기도 하고, 인덱스가 메모리에 안 올라가서 먼저 막히기도 합니다. 처리량도 같이 묶입니다. 한 대의 CPU(Central Processing Unit)와 네트워크 카드가 감당하는 만큼이 그 시스템 전체의 상한이 됩니다.

첫 번째로 떠오르는 길은 서버를 더 큰 것으로 바꾸는 것입니다. 이것을 수직 확장이라고 부릅니다. 이 길에는 끝이 있습니다. 살 수 있는 가장 큰 기계가 있고, 거기서 멈춥니다. 남는 길은 서버를 여러 대로 늘리는 것입니다. 그런데 같은 데이터를 모든 서버에 복사해 두는 것으로는 저장할 수 있는 총량이 늘지 않습니다. 서버마다 같은 것을 들고 있기 때문입니다. 읽기는 여러 대가 나눠 받을 수 있어도, 담을 수 있는 양과 써 넣는 양은 한 대의 몫에 그대로 묶여 있습니다. 같은 데이터를 복사해 두는 것을 복제라고 부릅니다.

그래서 데이터 자체를 겹치지 않게 나눠 서버마다 다른 몫을 맡깁니다. 그렇게 나눈 조각 하나를 샤드라고 부릅니다. 나누는 행위 쪽을 가리킬 때는 샤딩이라고 부릅니다. 나누는 축과 복사하는 축은 서로 다릅니다. 나누면 서버마다 맡는 몫이 줄고, 복사하면 같은 몫이 여러 벌이 됩니다.

flowchart TD
    D["전체 데이터"] -->|나눈다| S1["샤드 1"]
    D -->|나눈다| S2["샤드 2"]
    S1 -->|복사한다| R1["샤드 1 의 복사본"]
    S2 -->|복사한다| R2["샤드 2 의 복사본"]

예시

검색엔진 — Elasticsearch 의 샤드

Elasticsearch 공식 문서는 샤드를 저장의 기본 단위로 둡니다. 모든 인덱스는 데이터와 작업 부하를 클러스터의 노드들에 분산하기 위해 하나 이상의 샤드로 나뉩니다. Elasticsearch 는 모든 문서를 한 자리에 두지 않습니다. 대신 인덱스를 하나 이상의 샤드로 나누고 그 샤드들을 클러스터의 노드들에 분산합니다.

각 샤드는 자족적인 Apache Lucene 인덱스입니다. 한 샤드가 효율적으로 다룰 수 있는 데이터 양에는 실용적인 한계가 있어서, 데이터를 여러 샤드에 나누는 것이 개별 샤드를 성능 있게 유지해 준다고 적습니다. 그 샤드들을 클러스터 노드에 분산하는 것이 수평 확장과 중복성을 더합니다.

크기 권고에는 실제 수치가 붙습니다.

문서 수   샤드당 2억 건까지를 목표로
크기     10GB ~ 50GB

샤드마다 클러스터 관리와 검색 성능 양쪽에서 약간의 오버헤드가 따릅니다. 문서는 샤드의 물리 크기에 하드 리밋은 없다고 적습니다. 이론상 각 샤드는 20억 건을 조금 넘게 담을 수 있습니다. 다만 경험상 샤드당 문서 수를 2억 미만으로 유지하는 한 10GB 에서 50GB 사이의 샤드가 많은 사례에서 잘 동작한다고 적습니다. Elasticsearch 샤드 하나가 별개의 Lucene 인덱스라서 Lucene 의 max_doc 한계를 함께 집니다. 그 값은 2,147,483,519 로, (2^31)-129 입니다.

복사본에도 샤드라는 이름이 그대로 붙습니다. 프라이머리 샤드를 다른 노드들의 레플리카 샤드로 수평 확장하면 인덱스가 큰 트래픽을 효율적으로 다룰 수 있습니다. 레플리카 샤드는 내결함성을 줍니다. 개별 노드의 응답이 실패해도 데이터를 계속 쓸 수 있게 해 줍니다.

문서 데이터베이스 — MongoDB 의 샤드

MongoDB 매뉴얼은 샤디드 클러스터의 구성요소 가운데 하나로 샤드를 듭니다. 각 샤드는 샤딩된 데이터의 부분집합을 담습니다. 그리고 각 샤드는 반드시 레플리카 셋으로 배포되어야 합니다.

MongoDB 는 컬렉션 수준에서 샤딩합니다. 컬렉션 데이터를 클러스터의 샤드들에 분산합니다. 어느 문서가 어느 샤드로 갈지는 샤드 키가 정합니다. 샤드 키는 문서의 필드 하나 또는 여러 필드로 이뤄집니다.

실제 호출은 이렇습니다.

sh.shardCollection()

이 메서드를 실행하면 밸런서가 컬렉션 데이터를 클러스터의 다른 샤드들로 분산하기 시작합니다. 한 샤드는 한 시점에 청크 마이그레이션 하나에만 참여할 수 있습니다.

가용성은 배포 형태에서 나옵니다. 컨피그 서버와 샤드를 레플리카 셋으로 배포하는 것이 가용성을 높여 줍니다. 하나 이상의 샤드 레플리카 셋이 완전히 불가용해져도 샤디드 클러스터는 부분적인 읽기와 쓰기를 계속 수행할 수 있습니다.

키-값 저장소 — Redis 클러스터의 해시 슬롯

Redis 클러스터 명세는 키 분배 모델부터 적습니다. 클러스터의 키 공간은 16384개의 슬롯으로 나뉩니다. 이것이 클러스터 크기의 상한을 마스터 노드 16384개로 사실상 정합니다. 다만 권장하는 최대 노드 수는 1000개 정도라고 덧붙입니다. 클러스터의 각 마스터 노드는 16384개 해시 슬롯의 부분집합을 담당합니다.

키를 해시 슬롯에 대응시키는 기본 알고리즘은 이렇습니다.

HASH_SLOT = CRC16(key) mod 16384

CRC16 은 CRC(Cyclic Redundancy Check) 16비트 값을 뜻합니다. 키를 이 값으로 바꾼 뒤 16384로 나눈 나머지가 그 키가 속할 슬롯 번호입니다.

Redis 는 샤드를 직접 조회하는 명령도 둡니다. CLUSTER SHARDS 는 클러스터의 샤드에 대한 상세를 돌려줍니다. 여기서 샤드는 같은 슬롯 집합을 서비스하면서 서로 복제하는 노드들의 모음으로 정의됩니다. 샤드는 한 시점에 마스터를 하나만 가질 수 있고, 레플리카는 여럿일 수도 없을 수도 있습니다. 명령은 샤드의 배열을 돌려주고, 각 샤드는 두 필드를 갖습니다.

slots   이 샤드가 서비스하는 슬롯 범위의 목록
nodes   이 샤드 안의 모든 노드 목록

클라이언트가 MOVED 리다이렉션을 받았을 때 CLUSTER SHARDS 로 클라이언트 쪽 클러스터 배치도를 통째로 새로 고치는 길도 있습니다. 예전에 쓰던 CLUSTER SLOTS 는 폐기 예정입니다.

경계

한 서버 안에서 큰 테이블을 여러 조각으로 쪼갠 것도 샤드인가. 아닙니다.

PostgreSQL 공식 문서는 파티셔닝을 논리적으로 하나인 큰 테이블을 더 작은 물리 조각으로 쪼개는 것이라고 적습니다. 파티션은 파티션된 테이블에 딸린, 그 밖에는 평범한 테이블입니다. 각 파티션은 자기 파티션 경계가 정한 데이터의 부분집합을 담습니다. 파티션된 테이블에 넣은 모든 행은 파티션 키 열의 값에 따라 알맞은 파티션 하나로 보내집니다.

겹치지 않는 부분집합을 조각마다 담고 값으로 갈 곳을 정한다는 점까지는 샤드와 같습니다. 그런데 이 문서가 적는 범위는 거기까지입니다. 조각을 여러 서버에 흩는다는 이야기는 나오지 않습니다. 샤드 쪽 문서는 그 자리를 명시합니다. Elasticsearch 는 인덱스를 하나 이상의 샤드로 나누고 그 샤드들을 클러스터의 노드들에 분산한다고 적습니다. MongoDB 는 각 샤드가 반드시 레플리카 셋으로 배포되어야 한다고 적습니다.

가르는 선은 조각으로 나눴느냐가 아닙니다. 그 조각들을 여러 노드가 나눠 지느냐입니다.

관련 항목

샤드를 나누고 넓히는 방식과 대안

샤딩 · 샤드 키 · 수평 분할 · 라우팅 · 해시 슬롯 · 일관성 해싱 · 수평 확장 · 수직 확장

샤드와 대립하는 파티션 개념

파티션 · 파티셔닝 · 파티션 키 · 기본 키

샤드를 감싸는 인프라 구성요소

노드 · 마스터 노드 · 클러스터 · 컨피그 서버 · 밸런서

샤드와 축이 다른 복제 개념

레플리카 · 레플리카 셋 · 레플리카 샤드 · 프라이머리 샤드 · 복제 · 고가용성

샤드를 재배치하는 동작과 단위

리밸런싱 · 청크 · 청크 마이그레이션 · 리샤딩 · MOVED 리다이렉션

여러 샤드에 걸치는 연산이 치르는 대가

핫스팟 · 교차 샤드 조인 · 팬아웃 쿼리 · 분산 트랜잭션

샤드가 속하는 상위 단위

분산 시스템 · 데이터베이스 · 인덱스 · 컬렉션

샤드를 실제로 구현·채택한 제품

Elasticsearch · MongoDB · Redis · PostgreSQL · Lucene

다른 이름: shard