- Published on
DB 샤딩 & 파티셔닝 완전 가이드 2025: 수평 확장, Range/Hash/Directory, 리샤딩, Vitess
- Authors

- Name
- Youngju Kim
- @fjvbn20031
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 좋은 샤드 키의 조건
- 균등 분포 — 데이터가 모든 샤드에 균등 분산
- 불변 — 한 번 정해지면 거의 안 변함
- 쿼리 패턴 일치 — 자주 함께 조회되는 데이터는 같은 샤드
- 카디널리티 높음 — 충분히 많은 고유 값
- 단조 증가 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 필요.
전략:
- Co-location: 같은 user_id의 users와 orders를 같은 샤드에
- Denormalization: orders에 user 정보 복사
- 분산 쿼리 엔진: Vitess, Citus가 자동 처리
- 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:
- 새 샤드에 데이터 복사
- 짧은 maintenance window
- 트래픽 전환
- 옛 샤드 삭제
단점: 다운타임.
2. CDC + Dual Write:
- CDC로 옛 → 새 샤드 동기화
- 애플리케이션이 옛 + 새 둘 다 쓰기 (dual write)
- 데이터 일치 확인
- 읽기를 새로 전환
- 옛 샤드 폐기
무중단, 복잡.
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
- 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 성숙도 우려
퀴즈
1. 샤딩이 read replica로 해결할 수 없는 이유는?
답: Read replica는 읽기만 분산합니다. 쓰기는 여전히 Primary 1대가 처리. 쓰기가 병목인 시스템 (예: 일일 10억 INSERT)은 read replica로 해결 불가능. 샤딩만이 쓰기를 여러 머신에 분산할 수 있습니다. 단, 샤딩은 복잡도가 매우 높으므로 read replica + 캐싱 + 인덱스 최적화로 해결 가능한지 먼저 검토해야 합니다.
2. Hash sharding의 장단점은?
답: 장점: 균등 분포 (hash가 잘 만들어졌으면). 단조 증가 키도 안전. 단점: 범위 쿼리 불가능 (WHERE id BETWEEN ...). 샤드 추가 시 거의 모든 데이터 재분배 (% num_shards가 변하므로). 해결책: Consistent Hashing — 샤드 추가/제거 시 일부 데이터(1/N)만 이동. Cassandra, DynamoDB, Riak가 사용. Virtual nodes로 더 균등한 분포.
3. Hot Spot 문제를 어떻게 해결하나요?
답: (1) 샤드 키 변경 — 가장 좋지만 재샤딩 필요 (어려움), (2) Composite key — hash(user_id + timestamp_bucket)로 시간/사용자 분산, (3) 하위 샤딩 — Hot 샤드를 더 잘게 분할 ("whale shard"), (4) 캐싱 — 핫 데이터를 Redis로, (5) 읽기 복제본 — 읽기 부하 분산. 가장 흔한 hot spot: 인기 사용자, 인기 상품, 단조 증가 키. 샤드 키 선택 시 반드시 hot spot 시나리오 검토.
4. Vitess가 MySQL 분산의 표준이 된 이유는?
답: (1) YouTube에서 시작 — 거대한 규모에서 검증됨, (2) MySQL 호환 — 기존 코드/도구 그대로 사용, (3) 자동 샤딩 — 키 기반 라우팅, (4) VReplication — 무중단 마이그레이션과 리샤딩, (5) CNCF 졸업 — 클라우드 네이티브 표준, (6) 검증된 사용자 — Slack, GitHub, Square. 단점은 분산 트랜잭션이 약한 편 (Saga 패턴 권장). PostgreSQL 사용자는 Citus가 유사한 역할.
5. 언제 NewSQL (CockroachDB) vs 수동 샤딩?
답: NewSQL (CockroachDB, YugabyteDB) 선택: 새 프로젝트, 강한 일관성 필요 (분산 ACID), 운영 인력 부족, PostgreSQL 호환 가능. 수동 샤딩 (Vitess + MySQL) 선택: 기존 MySQL 시스템, 극단적 성능 필요, NewSQL 성숙도 우려, 더 큰 통제력 원함. 현실: 새 시스템은 점점 NewSQL로, 기존 거대 시스템은 Vitess 유지. 둘 다 valid한 선택이며 트레이드오프에 따라 결정.
참고 자료
- Designing Data-Intensive Applications — Martin Kleppmann (샤딩 챕터)
- Vitess — YouTube 공식
- Citus Data
- CockroachDB Docs
- YugabyteDB
- TiDB
- Slack's Data Stores — Vitess 마이그레이션
- GitHub MySQL → Vitess
- Stripe's Sharding Approach
- Discord's Trillion Messages — Cassandra 사용
- Pinterest Sharding