한 DB 의 데이터가 100 TB. write 부하가 한 노드 한도 초과. replication 만으로는 안 됨 — 모든 replica 가 같은 데이터 보유. 해결: sharding — 데이터를 여러 노드에 쪼개기. hash vs range, consistent hashing, hot shard, cross-shard join — 이 가이드는 그 메커니즘과 함정을 정리한다.
Sharding vs Replication — 다른 문제
Replication: 같은 데이터 N 노드 복사
- 가용성 ↑
- 읽기 처리량 ↑ (read replica)
- write 처리량 = 한 노드의 한계 (모든 write 가 leader 거침)
Sharding: 다른 데이터를 다른 노드에
- write 처리량 ↑ (N 노드 병렬)
- 데이터 용량 ↑ (N × disk)
- 가용성은 sharding 만으로 안 됨 → replication 도 결합
실전: shard + replica 결합 (각 shard 가 자체 replica set)
예: MongoDB sharded cluster = 3 shards × 3 replica = 9 노드Partition 전략 1 — Range-based
user_id 기준 range partition:
shard-A: user_id 0 ~ 999_999
shard-B: user_id 1M ~ 1.999M
shard-C: user_id 2M ~ ∞
장점:
- range scan 효율 ("user 1000-2000 조회" → shard-A 만 hit)
- 신규 데이터 (auto-increment) 가 한 shard 에 → 정렬 우수
단점:
- ⚠ HOT SHARD — 최근 user 만 활성이면 shard-C 만 부하 폭증
- imbalance 발생 시 split 필요
사용: HBase, BigTable, MongoDB (default), DynamoDB (sort key)Partition 전략 2 — Hash-based
hash(user_id) % N 로 shard 결정:
hash(user_42) = 0x8a3f... mod 3 = 1 → shard-B
hash(user_43) = 0x2c19... mod 3 = 0 → shard-A
hash(user_44) = 0xf501... mod 3 = 2 → shard-C
장점:
- 균등 분산 (random hash 의 성질)
- hot key 자연 분산 (인접 ID 가 다른 shard)
단점:
- range scan 불가 ("user 1000-2000" 는 모든 shard 조회 필요)
- ⚠ resharding 함정 — N 변경 (3 → 4) 시 모든 데이터의 80% 가 옮겨가야
사용: DynamoDB partition key, Cassandra, MongoDB hashed shard keyConsistent Hashing — resharding 의 해결책 (1995)
hash 결과를 0..2^32 의 ring 으로 매핑:
0
┌───┴───┐
│ shard │
│ A │
⊕ (0~85) │ ← user_X → hash 200 → 다음 shard 인 B
│ │
│ shard │
│ B │
│(85~170)│
│ │
│ shard │
│ C │
│(170~255)│
│ │
└───────┘
ring 위에서 시계방향 다음 shard 의 데이터가 됨.
새 shard 추가 (D, position 128):
- 기존 B (85~170) 의 일부 (128~170) 만 D 로 옮김
- 나머지 shard A, C 는 영향 0
→ N → N+1 변경 시 대략 1/N 데이터만 이동 (vs 단순 mod 의 80%).
virtual node (각 shard 가 ring 의 여러 위치) 로 균등 분산 개선 — Amazon Dynamo / Cassandra 의 표준 트릭.Hot Shard — 가장 흔한 운영 문제
사례 1 — 시간 기반 ID
shard by created_at month → 이번 달 데이터만 hot
사례 2 — user 분포 skew
hash by user_id → "celebrity user" (1 user 가 100x 트래픽)
→ 그 user 가 속한 shard 만 부하
사례 3 — auto-increment with range
insertion → 항상 last shard 에 추가 → write hot
해결:
- shard key 재설계 (composite key, salt)
- celebrity 만 별도 shard / cache (Twitter 의 fanout 전략)
- 시간 기반은 일별 shard 가 아닌 hash + 시간 prefix
- AWS DynamoDB 의 adaptive capacity — hot partition 자동 추가 capacityRebalancing — downtime 없이 옮기기
shard 추가 시 데이터 이동 단계:
1. 새 shard 등록 (routing layer 에서 "준비 중" 상태)
2. 옮길 데이터 식별 (consistent hashing 으로 1/N 만)
3. 데이터 복사 (옛 shard → 새 shard, 백그라운드)
4. 데이터 검증 (checksum / 행 수)
5. routing cut-over (atomic, 한 시점에 새 shard 로)
6. 옛 shard 의 옮긴 데이터 정리
함정:
- cut-over 시점에 in-flight write 처리 — dual-write 또는 lock
- routing 정보 캐싱이 stale → 잘못된 shard 로 query
- 옛 shard 에서 옮긴 데이터를 미리 지우면 → cut-over 실패 시 복구 불가
- 백그라운드 복사가 production 부하 영향 (rate limit 필수)
DBMS 가 자동 처리: MongoDB chunks, Vitess vreplication, CockroachDB rebalancingCross-Shard Join — 용
-- 단일 DB 에서는 자연스러움
SELECT u.name, o.total
FROM users u JOIN orders o ON o.user_id = u.id
WHERE u.region = 'KR';
-- shard 된 환경:
users 는 shard-A, B, C 에 분산
orders 는 shard-X, Y, Z 에 분산 (다른 shard key 일 수 있음)
→ JOIN 을 어디서?
- shard 1 곳 골라서 다른 shard 데이터 fetch → 그 노드 메모리 폭증
- 모든 shard 에서 부분 결과 → coordinator 가 merge → coordinator hot
- application 에서 두 query 분리 → fetch → in-memory merge (복잡, slow)
해결 패턴:
1. denormalize — 자주 join 하는 field 를 미리 복제 (소량 데이터)
2. co-locate — users 와 orders 를 같은 shard key 로 (user_id) → 같은 shard
3. global table — 작은 reference 테이블 (region, category) 만 모든 shard 에 복제
4. materialized view — 미리 join 한 결과 별도 저장
→ 결국 "shard 하면 join 비싸진다" 는 게 가장 큰 운영 부담.실제 시스템들
| 시스템 | 전략 | 비고 |
|---|---|---|
| DynamoDB | hash (partition key) | adaptive capacity 로 hot partition 완화 |
| Cassandra | consistent hashing + virtual nodes | linear scaling 의 모범 |
| MongoDB | range or hashed | chunk 단위 자동 split / rebalance |
| Vitess (YouTube) | range (sharded MySQL) | 전통 MySQL 위에 sharding layer |
| CockroachDB | range (per-key) | 자동 split + 자동 rebalance |
| Spanner | range (per-tablet) | load 따라 split |
흔한 함정
- 너무 일찍 shard — 100 GB 미만 단일 DB 도 보통 충분. 운영 복잡도 ↑↑ 가 이른 sharding 의 최대 비용.
- 잘못된 shard key 선택 — 바꾸려면 모든 데이터 재배치. shard key 결정은 거의 불가역.
- cross-shard transaction 가정 — 2PC 의 latency + 부분 fail 위험. shard 안에서만 transaction 가능하게 설계.
- auto-increment ID + sharding — 모든 write 가 last shard 로. UUID v4 또는 snowflake ID 사용.
- monitoring 의 어려움 — shard 별 부하 모니터링 필수. 한 shard 만 hot 이어도 전체 latency 영향.
마무리
Sharding 은 horizontal scaling 의 정공법이지만 운영 복잡도가 큰 도구. 단일 DB + replication 으로 가능한 한 버티고, 그래도 한계 도달 시 shard. 그리고 한 번 shard 하면 join · transaction 의 비용이 영구히 ↑.
consistent hashing + virtual node + replica per shard 가 modern distributed DB 의 기본 패턴 — DynamoDB / Cassandra / CockroachDB 모두 이 변형.