Skip to content

필사 모드: DB 샤딩 & 파티셔닝 완전 가이드 2025: 수평 확장, Range/Hash/Directory, 리샤딩, Vitess

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

TL;DR

- **샤딩 = 수평 확장의 답**: 단일 DB로 안 되는 규모에서 필수

- **샤드 키 선택이 운명**: 잘못 선택하면 hot spot, 재샤딩 지옥

- **3대 전략**: Range, Hash, Directory (Lookup) — 각각 장단점

- **분산 트랜잭션이 어려움**: 2PC는 느림, Saga가 현실적

- **Vitess가 표준**: YouTube/Slack/GitHub이 사용. MySQL 위의 분산 레이어

1. 샤딩이란?

1.1 단일 DB의 한계

[Single DB]

├─ CPU: 1 머신만큼만

├─ RAM: 256GB? 512GB?

├─ 디스크: 30TB

└─ 네트워크: 25 Gbps

→ 결국 한계에 도달

**수직 확장 (Vertical Scaling)**:

- 더 큰 머신

- 한계 있음 (가장 큰 EC2 = 24TB RAM, $20+/시간)

- 단일 장애점

**수평 확장 (Horizontal Scaling)**:

- 여러 머신

- 무한 확장

- 복잡도 증가

1.2 Read Replica로 해결?

[Primary] (쓰기)

↓ replication

[Replica 1] [Replica 2] [Replica 3] (읽기)

**도움**: 읽기 트래픽 분산.

**한계**: **쓰기는 여전히 Primary 1대**. 쓰기가 병목이면 도움 안 됨.

→ **샤딩**이 필요합니다.

1.3 샤딩의 정의

**샤딩** = 데이터를 여러 독립적 DB(샤드)에 분산.

[users 테이블]

↓ shard by user_id

[Shard 1: user_id 1-1M]

[Shard 2: user_id 1M-2M]

[Shard 3: user_id 2M-3M]

...

각 샤드는 **완전히 독립**적인 DB. 자체 CPU, RAM, 디스크.

1.4 샤딩의 효과

| | 단일 DB | 100 샤드 |

|---|---|---|

| 데이터 | 1 TB | 100 TB |

| 쓰기 TPS | 10,000 | 1,000,000 |

| 비용 | $10K/월 | $50K/월 |

| 복잡도 | 낮음 | **매우 높음** |

**100배 성능 + 5배 비용 = ROI 좋음**. 단, **복잡도가 큰 문제**.

2. 샤드 키 선택 — 가장 중요한 결정

2.1 좋은 샤드 키의 조건

1. **균등 분포** — 데이터가 모든 샤드에 균등 분산

2. **불변** — 한 번 정해지면 거의 안 변함

3. **쿼리 패턴 일치** — 자주 함께 조회되는 데이터는 같은 샤드

4. **카디널리티 높음** — 충분히 많은 고유 값

5. **단조 증가 X** — auto-increment ID는 hot spot 위험

2.2 흔한 샤드 키 후보

**user_id**:

- ✅ 사용자 데이터를 한 샤드에 모음 (관련 데이터 같이)

- ❌ 큰 사용자가 hot spot

- ❌ user 간 JOIN 어려움

**created_at**:

- ❌ 단조 증가 → 모든 새 데이터가 한 샤드에 (hot spot)

- 시계열 데이터에는 OK

**hash(id)**:

- ✅ 균등 분포

- ❌ 범위 쿼리 불가능

- ❌ 관련 데이터가 다른 샤드

**country**:

- ✅ Geographic 효율

- ❌ 매우 불균등 (US가 거대, 모나코는 작음)

**organization_id**:

- ✅ B2B SaaS에 이상적

- ❌ 큰 조직이 hot spot

2.3 Slack의 사례

Slack의 **샤드 키 = workspace_id**.

**이유**:

- 같은 workspace의 모든 데이터를 한 샤드에 → 빠른 조회

- workspace 간 JOIN 거의 없음

- workspace 단위로 자연스러운 격리

**단점**: 거대 enterprise workspace가 단일 샤드 압도 → "Whale shard" 문제.

**해결**: 거대 workspace는 자체 전용 샤드.

3. 샤딩 전략

3.1 Range Sharding

데이터를 키의 **범위**로 분할.

Shard 1: id 1 ~ 1,000,000

Shard 2: id 1,000,001 ~ 2,000,000

Shard 3: id 2,000,001 ~ 3,000,000

**장점**:

- 범위 쿼리 효율 (`WHERE id BETWEEN 500000 AND 600000`)

- 단순한 라우팅

- 새 샤드 추가 쉬움

**단점**:

- **Hot spot 위험**: 단조 증가 키면 새 데이터가 모두 마지막 샤드에

- 불균등 분포 가능

**사용 사례**: 시계열 데이터, BigTable, HBase

3.2 Hash Sharding

샤드 키의 **hash**로 분할.

shard_id = hash(user_id) % num_shards

**장점**:

- **균등 분포** — hash가 잘 만들어졌으면

- 단조 증가 키도 안전

**단점**:

- 범위 쿼리 불가능 (`WHERE id BETWEEN ...`)

- 새 샤드 추가 시 거의 모든 데이터 재분배 (`% num_shards`가 변하니까)

**해결**: **Consistent Hashing** — 샤드 추가/제거 시 일부 데이터만 이동.

3.3 Consistent Hashing

[원형 해시 공간]

Shard A

/

Shard D

\

Shard B

/

Shard C

각 샤드와 데이터를 같은 해시 공간에 매핑. 데이터는 시계방향으로 가장 가까운 샤드에.

**샤드 추가 시**: 해당 부분만 재분배 (전체의 1/N).

**Virtual Nodes**: 각 샤드를 여러 가상 노드로 표현 → 더 균등.

**사용**: Cassandra, DynamoDB, Riak, Memcached.

3.4 Directory-Based Sharding

**Lookup 테이블**로 어떤 데이터가 어떤 샤드에 있는지 명시적 매핑.

[Lookup]

user_1 → Shard A

user_2 → Shard B

user_3 → Shard A

...

**장점**:

- **유연**: 임의의 매핑 가능

- 균등하지 않은 분포도 처리

- 마이그레이션 쉬움

**단점**:

- **Lookup 자체가 병목** (캐싱 필수)

- 추가 인프라 (Redis, Consul)

- 단일 장애점

**사용**: Vitess (이런 방식의 변형)

3.5 Geographic Sharding

위치별 샤드:

- US 사용자 → US 샤드

- EU 사용자 → EU 샤드

- Asia 사용자 → Asia 샤드

**장점**:

- 사용자에 가까이 → 낮은 latency

- 규제 준수 (GDPR — EU 데이터를 EU에)

- 자연스러운 분할

**단점**:

- 사용자 이동 시 어려움

- 글로벌 쿼리 어려움

- 매우 불균등 (지역별 사용자 수)

3.6 비교표

| 전략 | 균등성 | 범위 쿼리 | 추가 | 쿼리 패턴 |

|---|---|---|---|---|

| **Range** | 낮음 | ✅ | 쉬움 | 범위 |

| **Hash** | 높음 | ❌ | 어려움 | 정확 |

| **Consistent Hash** | 높음 | ❌ | **쉬움** | 정확 |

| **Directory** | 높음 | 부분 | 쉬움 | 자유 |

| **Geographic** | 낮음 | 부분 | 보통 | 지역 |

4. Hot Spot 문제

4.1 Hot Spot이란?

특정 샤드에 트래픽/데이터가 집중되는 현상.

**원인**:

- 잘못된 샤드 키 (인기 사용자, 인기 상품)

- 단조 증가 키 (created_at)

- 불균등 분포 (몇몇 거대 조직)

4.2 영향

[Shard 1: 10% 트래픽]

[Shard 2: 5% 트래픽]

[Shard 3: 80% 트래픽] ← Hot spot! 죽음

[Shard 4: 5% 트래픽]

전체 시스템이 **가장 약한 샤드에 의해 결정**됩니다.

4.3 탐지

-- 샤드별 데이터 양

SELECT shard_id, COUNT(*) as row_count

FROM users

GROUP BY shard_id;

-- 샤드별 쿼리 수 (애플리케이션 메트릭)

**경고 신호**:

- 한 샤드가 평균보다 5배+ 큼

- 한 샤드의 CPU/IO가 100%

4.4 해결책

**1. 샤드 키 변경**

- 가장 좋지만 가장 어려움 (재샤딩 필요)

**2. Composite Key**

shard_key = hash(user_id + timestamp_bucket)

시간 기반 + 사용자 기반 결합.

**3. 하위 샤딩 (Sub-sharding)**

- Hot 샤드를 더 잘게 분할

- "Whale shard" 처리

**4. 캐싱**

- 핫 데이터를 Redis로

- DB 부하 감소

**5. 읽기 복제본**

- 읽기 부하 분산

- 쓰기는 여전히 hot

4.5 예시: Twitter의 Celebrity Problem

**문제**: 한 셀럽 사용자(예: 일론 머스크)가 트윗 → 수억 followers의 timeline 업데이트.

**해결**:

- **Fan-out on write** (일반 사용자): 트윗 시 followers의 timeline에 미리 작성

- **Fan-in on read** (셀럽): 트윗 시 timeline 안 만듦, 읽을 때 가져옴

- **하이브리드**: 활성 followers는 fan-out, 비활성은 fan-in

5. 분산 쿼리의 어려움

5.1 단일 샤드 쿼리

SELECT * FROM users WHERE user_id = 12345;

→ user_id로 샤드 결정 → 해당 샤드만 쿼리. **매우 빠름**.

5.2 Cross-Shard 쿼리

SELECT COUNT(*) FROM users WHERE country = 'KR';

→ **모든 샤드에 쿼리** → 결과 합산. **느림 + 부하**.

5.3 JOIN의 어려움

SELECT u.name, o.total

FROM users u

JOIN orders o ON o.user_id = u.user_id

WHERE u.country = 'KR';

users와 orders가 다른 샤드에 있으면? **분산 JOIN** 필요.

**전략**:

1. **Co-location**: 같은 user_id의 users와 orders를 같은 샤드에

2. **Denormalization**: orders에 user 정보 복사

3. **분산 쿼리 엔진**: Vitess, Citus가 자동 처리

4. **CQRS**: 쿼리용 별도 DW (Snowflake) 사용

5.4 분산 트랜잭션

def transfer(from_user, to_user, amount):

두 사용자가 다른 샤드에 있을 수 있음

db.update(f"... WHERE user_id={from_user}", -amount)

db.update(f"... WHERE user_id={to_user}", +amount)

**문제**: 첫 update 성공 + 두 번째 실패 → 돈 사라짐.

**해결**:

**1. 2PC (Two-Phase Commit)**:

- Prepare → Commit

- 모든 샤드가 동의해야 commit

- **느림 + 단일 장애점** → 비추천

**2. Saga 패턴**:

- 보상 트랜잭션

- Eventually consistent

- 실전 표준

**3. 같은 샤드에 보장**:

- 가능하면 전송자/수신자를 같은 샤드에

- 항상 가능하지는 않음

6. 리샤딩 — 가장 무서운 작업

6.1 왜 리샤딩이 어려운가?

- **데이터 이동**: 수십 TB 이동

- **무중단**: 사용자 영향 X

- **롤백**: 문제 시 복구

- **일관성**: 이동 중 쓰기/읽기 처리

6.2 리샤딩 시나리오

**1. 샤드 추가**: 4 샤드 → 8 샤드

**2. 샤드 분할**: 거대 샤드를 둘로

**3. 샤드 병합**: 작은 샤드 합치기

**4. 샤드 키 변경**: 가장 어려움

6.3 리샤딩 패턴

**1. Bulk Copy + Switchover**:

1. 새 샤드에 데이터 복사

2. 짧은 maintenance window

3. 트래픽 전환

4. 옛 샤드 삭제

**단점**: 다운타임.

**2. CDC + Dual Write**:

1. CDC로 옛 → 새 샤드 동기화

2. 애플리케이션이 옛 + 새 둘 다 쓰기 (dual write)

3. 데이터 일치 확인

4. 읽기를 새로 전환

5. 옛 샤드 폐기

**무중단**, 복잡.

**3. Online Migration**:

- Vitess의 VReplication

- 자동화된 무중단 마이그레이션

- 진행률 모니터링

6.4 사례: Slack의 샤딩 진화

- **2017**: 단일 MySQL → 복제본

- **2018**: 첫 샤딩 (workspace_id)

- **2020**: Vitess 도입

- **2022**: Whale workspace 처리

- **2024**: 수천 샤드, 페타바이트

**교훈**: 샤딩은 한 번에 끝나지 않음. **지속적 진화**.

7. Vitess — MySQL 위의 분산 레이어

7.1 Vitess란?

YouTube가 만든 MySQL 샤딩 솔루션. **CNCF 졸업**.

[Client]

[VTGate] (쿼리 라우터)

[VTTablet] [VTTablet] [VTTablet]

↓ ↓ ↓

[MySQL] [MySQL] [MySQL]

**장점**:

- **MySQL 호환** — 기존 코드 그대로

- **자동 샤딩** — 키 기반 라우팅

- **스키마 마이그레이션** — 안전한 DDL

- **VReplication** — 무중단 리샤딩

- **검증된 규모** — YouTube, Slack, GitHub, Square

7.2 사용 회사

- **YouTube** (창시자, 페타바이트)

- **Slack** (대규모)

- **GitHub** (MySQL → Vitess 전환)

- **Square**

- **Pinterest**

- **JD.com** (중국 최대 e-commerce)

7.3 VSchema 예시

{

"sharded": true,

"vindexes": {

"hash": {

"type": "hash"

}

},

"tables": {

"users": {

"column_vindexes": [

{

"column": "user_id",

"name": "hash"

}

]

}

}

}

→ VTGate가 자동으로 user_id 기반 샤딩.

8. 다른 분산 DB 옵션

8.1 Citus (PostgreSQL)

PostgreSQL 확장. 분산 쿼리, 분산 트랜잭션 지원.

SELECT create_distributed_table('events', 'user_id');

**장점**: PostgreSQL 호환, SQL 그대로.

**단점**: PostgreSQL 한계 (Vitess보다 성숙도 낮음).

8.2 CockroachDB

처음부터 분산 SQL DB로 설계.

**장점**:

- **PostgreSQL 호환**

- **자동 샤딩** (range-based)

- **글로벌 분산** 지원

- **분산 ACID 트랜잭션**

**단점**:

- 일부 PG 기능 미지원

- 더 비싼 운영

- 학습 곡선

**사용**: DoorDash, Bose, Comcast.

8.3 YugabyteDB

CockroachDB와 비슷. **PostgreSQL 호환 + Cassandra 호환** 동시.

8.4 TiDB

**MySQL 호환** + 자동 분산. 중국에서 인기.

8.5 비교표

| | Vitess | Citus | CockroachDB | YugabyteDB | TiDB |

|---|---|---|---|---|---|

| **기반** | MySQL | PostgreSQL | 자체 | 자체 | 자체 |

| **호환성** | MySQL | PostgreSQL | PostgreSQL | PG + CQL | MySQL |

| **분산 트랜잭션** | 제한 | ✅ | ✅ | ✅ | ✅ |

| **자동 샤딩** | 수동 키 | 수동 키 | **자동** | 자동 | 자동 |

| **운영 난이도** | 보통 | 낮음 | 보통 | 보통 | 보통 |

| **검증** | YouTube, Slack | 다수 | DoorDash | 다수 | 중국 큰 회사 |

9. 실전 — e-commerce 샤딩 설계

9.1 시나리오

- 1억 사용자

- 일일 1000만 주문

- 단일 PostgreSQL 한계 도달

9.2 분석

**테이블**:

- `users` (1억 행)

- `orders` (10억 행)

- `products` (100만 행)

- `reviews` (50억 행)

9.3 샤딩 결정

**1. users**:

- 샤드 키: `user_id` (hash)

- 16개 샤드

- 균등 분포

**2. orders**:

- 샤드 키: `user_id` (hash, **users와 같은 샤드**)

- 같은 사용자의 user + orders가 같은 샤드 → JOIN 빠름

**3. products**:

- 작음 (100만 행)

- **샤딩 X** — 단일 DB + 읽기 복제본

- 또는 모든 샤드에 복제

**4. reviews**:

- 샤드 키: `product_id` (hash)

- product 기준 분석에 적합

9.4 쿼리 패턴

-- 사용자 주문 (같은 샤드)

SELECT * FROM orders WHERE user_id = 12345;

-- ✅ 빠름

-- 사용자 정보 + 주문 (같은 샤드, JOIN OK)

SELECT u.*, o.*

FROM users u JOIN orders o ON o.user_id = u.user_id

WHERE u.user_id = 12345;

-- ✅ 빠름

-- 제품 리뷰 (다른 샤드)

SELECT * FROM reviews WHERE product_id = 67890;

-- ✅ 빠름

-- 사용자가 작성한 모든 리뷰 (cross-shard)

SELECT * FROM reviews WHERE user_id = 12345;

-- ⚠️ 느림 — 모든 reviews 샤드 검색

-- 해결: 비정규화. users 샤드에도 review 요약 저장.

9.5 인프라

[Application]

[ProxySQL / Vitess]

[16 user shards]

[16 order shards (co-located)]

[1 products DB + 5 read replicas]

[8 reviews shards]

9.6 모니터링

- 샤드별 쿼리 수

- 샤드별 디스크 사용량

- Cross-shard 쿼리 비율

- Hot spot 탐지

10. 샤딩의 함정과 교훈

10.1 너무 일찍 샤딩

**잘못된 결정**: 트래픽이 1000 QPS인데 샤딩.

**현실**:

- 단일 PostgreSQL = 50,000 QPS+

- Read replica = 200,000 QPS+

- 적절한 인덱스 + 캐싱 = 더 많이

→ **샤딩 전에 다른 모든 최적화를 먼저 시도**하세요.

10.2 잘못된 샤드 키

GitHub의 **첫 샤딩 시도**가 실패한 사례:

- repo_id로 샤딩 → 인기 repo가 hot spot

- Linus의 linux 저장소가 단일 샤드 압도

- **재샤딩 필요** (수개월의 작업)

**교훈**: 샤드 키는 **변경하기 매우 어렵다**. 처음에 신중히.

10.3 분산 트랜잭션 회피

분산 트랜잭션은 정말 어려움. 가능한 한 **같은 샤드 안에서만 트랜잭션** 보장.

**설계 시**: 쓰기 트랜잭션이 항상 단일 샤드 안에 들어가도록 데이터 모델 설계.

10.4 운영 복잡도

샤딩한 시스템은:

- 백업 복잡 (16개 샤드 동시)

- 모니터링 복잡

- 디버깅 어려움 (어느 샤드?)

- 마이그레이션 어려움

→ **자동화** 필수. **운영 인력** 충분히.

10.5 NewSQL이 답?

CockroachDB, YugabyteDB 같은 NewSQL은 자동 샤딩 + 분산 트랜잭션. **수동 샤딩의 복잡도 없음**.

**언제 NewSQL?**:

- 새 프로젝트

- 강한 일관성 필요

- 운영 인력 부족

**언제 수동 샤딩?**:

- 기존 MySQL/PostgreSQL

- 극단적 성능 필요

- NewSQL 성숙도 우려

퀴즈

**답**: Read replica는 **읽기**만 분산합니다. **쓰기는 여전히 Primary 1대**가 처리. 쓰기가 병목인 시스템 (예: 일일 10억 INSERT)은 read replica로 해결 불가능. 샤딩만이 **쓰기를 여러 머신에 분산**할 수 있습니다. 단, 샤딩은 복잡도가 매우 높으므로 read replica + 캐싱 + 인덱스 최적화로 해결 가능한지 먼저 검토해야 합니다.

**답**: **장점**: 균등 분포 (hash가 잘 만들어졌으면). 단조 증가 키도 안전. **단점**: 범위 쿼리 불가능 (`WHERE id BETWEEN ...`). **샤드 추가 시 거의 모든 데이터 재분배** (`% num_shards`가 변하므로). 해결책: **Consistent Hashing** — 샤드 추가/제거 시 일부 데이터(1/N)만 이동. Cassandra, DynamoDB, Riak가 사용. Virtual nodes로 더 균등한 분포.

**답**: (1) **샤드 키 변경** — 가장 좋지만 재샤딩 필요 (어려움), (2) **Composite key** — `hash(user_id + timestamp_bucket)`로 시간/사용자 분산, (3) **하위 샤딩** — Hot 샤드를 더 잘게 분할 ("whale shard"), (4) **캐싱** — 핫 데이터를 Redis로, (5) **읽기 복제본** — 읽기 부하 분산. 가장 흔한 hot spot: 인기 사용자, 인기 상품, 단조 증가 키. **샤드 키 선택 시 반드시 hot spot 시나리오 검토**.

**답**: (1) **YouTube에서 시작** — 거대한 규모에서 검증됨, (2) **MySQL 호환** — 기존 코드/도구 그대로 사용, (3) **자동 샤딩** — 키 기반 라우팅, (4) **VReplication** — 무중단 마이그레이션과 리샤딩, (5) **CNCF 졸업** — 클라우드 네이티브 표준, (6) **검증된 사용자** — Slack, GitHub, Square. 단점은 분산 트랜잭션이 약한 편 (Saga 패턴 권장). PostgreSQL 사용자는 Citus가 유사한 역할.

**답**: **NewSQL (CockroachDB, YugabyteDB) 선택**: 새 프로젝트, 강한 일관성 필요 (분산 ACID), 운영 인력 부족, PostgreSQL 호환 가능. **수동 샤딩 (Vitess + MySQL) 선택**: 기존 MySQL 시스템, 극단적 성능 필요, NewSQL 성숙도 우려, 더 큰 통제력 원함. **현실**: 새 시스템은 점점 NewSQL로, 기존 거대 시스템은 Vitess 유지. 둘 다 valid한 선택이며 트레이드오프에 따라 결정.

참고 자료

- [Designing Data-Intensive Applications](https://dataintensive.net/) — Martin Kleppmann (샤딩 챕터)

- [Vitess](https://vitess.io/) — YouTube 공식

- [Citus Data](https://www.citusdata.com/)

- [CockroachDB Docs](https://www.cockroachlabs.com/docs/)

- [YugabyteDB](https://docs.yugabyte.com/)

- [TiDB](https://docs.pingcap.com/tidb/stable)

- [Slack's Data Stores](https://slack.engineering/scaling-datastores-at-slack-with-vitess/) — Vitess 마이그레이션

- [GitHub MySQL → Vitess](https://github.blog/2021-09-27-partitioning-githubs-relational-databases-scale/)

- [Stripe's Sharding Approach](https://stripe.com/blog/online-migrations)

- [Discord's Trillion Messages](https://discord.com/blog/how-discord-stores-billions-of-messages) — Cassandra 사용

- [Pinterest Sharding](https://medium.com/pinterest-engineering/sharding-pinterest-how-we-scaled-our-mysql-fleet-3f341e96ca6f)

현재 단락 (1/391)

- **샤딩 = 수평 확장의 답**: 단일 DB로 안 되는 규모에서 필수

작성 글자: 0원문 글자: 9,763작성 단락: 0/391