에듀테크 프로젝트 대시보드
데이터베이스 샤딩
테이블 하나가 한 서버에 다 안 들어갈 만큼 커지면? 행(row)을 규칙에 따라 여러 서버에 나눠 담는다. 각 조각이 샤드(shard)다. 도서관 장서를 건물 여러 채에 분산 보관하는 것과 같다 — 문제는 "어떤 책을 어느 건물에?"를 정하는 규칙이다.
| 방식 | 무엇을 나누나 | 목적 / 한계 |
|---|---|---|
| 복제 (Replication) | 같은 데이터를 여러 서버에 복사 | 읽기 부하 분산·가용성 ↑ / 쓰기·용량은 그대로 |
| 수직 분할 | 테이블을 컬럼 기준으로 분리 (자주 쓰는 컬럼 / 큰 컬럼) | 단순하지만 한 테이블이 계속 크면 결국 한계 |
| 수평 분할 = 샤딩 | 테이블을 행 기준으로 여러 서버에 분배 | 용량·쓰기까지 분산 / 라우팅·조인·트랜잭션이 복잡해짐 |
파티셔닝 vs 샤딩: 한 DB 서버 안에서 테이블을 물리적으로 쪼개면 파티셔닝, 그 조각들을 서로 다른 머신에 흩으면 샤딩이라고 부른다. 규칙(범위·해시)은 똑같다.
샤드 키는 student_id(가입 순서대로 1씩 증가). 전략을 바꿔가며 레코드를 넣어보고,
샤드를 추가했을 때 기존 데이터가 얼마나 이사(재배치)해야 하는지 관찰하자.
shard = id % N. 분포는 고르지만 N이 바뀌면 거의 모든 행이
새 샤드로 이사해야 한다./consistent-hashing 참고).WHERE student_id = 8123): 라우터가 규칙을 계산해
딱 한 샤드에만 질의한다. 빠르다.WHERE name LIKE '김%'): 어느 샤드에 있는지 모르니
모든 샤드에 질의하고 결과를 합친다 → 스캐터-개더(scatter-gather). 샤드가 많을수록 느리고,
가장 느린 샤드가 전체 응답 시간을 결정한다./two-phase-commit)이 필요하거나, 아예 앱에서 조인한다.성별(2종)은 최악.user_id로 샤딩하면 그 샤드만 불탄다.auto_increment id나 타임스탬프를 범위 분할하면
최신 데이터가 항상 한 샤드로 → 쓰기 편중. 해시를 섞거나(hashed sharding),
(지역, 시간) 같은 복합 키를 쓴다.student_id로
같이 샤딩하면 조인이 한 샤드 안에서 끝난다(colocated).# 애플리케이션(또는 프록시)이 쿼리 전에 샤드를 계산한다 SHARDS = [db0, db1, db2, db3] def route(student_id): # 해시 샤딩: 분포는 고르지만 len(SHARDS)가 바뀌면 대이동 return SHARDS[hash(student_id) % len(SHARDS)] def get_student(student_id): return route(student_id).query( "SELECT * FROM students WHERE id = %s", student_id) def search_by_name(prefix): # 샤드 키가 없다 → 모든 샤드에 흩뿌리고(scatter) 모은다(gather) rows = [] for s in SHARDS: rows += s.query("SELECT * FROM students WHERE name LIKE %s", prefix + "%") return sorted(rows, key=lambda r: r.name) # 앱에서 병합·정렬
%N은 N이 바뀌는 순간 대부분 이사한다.
이동을 줄이려면 일관된 해시나 고정된 많은 논리 샤드(예: 1024개)를 소수의 물리 서버에 매핑한다.