오퍼(주문) 이벤트 테이블이 수억 행을 넘어 DB 한 대로는 더 못 버티게 됐다. 샤드를 나눠야 하는데, 키가 시간순으로 증가하는 ID라는 게 함정이다. 해시로 고르게 흩뿌릴지, 시간/ID 범위로 자를지 정해야 한다. 공장 센서 로그든 부동산 오퍼 이벤트든 "시간순 키 + 최근 N시간 조회"가 같이 오는 전형적인 상황.
언제: 단건 키 조회(order_id, user_id 점 조회)가 트래픽의 대부분일 때 — 대부분의 OLTP가 여기다. 특히 키가 시간순으로 증가하면(자동증가 ID, timestamp 접두) 해시가 쓰기를 전 샤드에 흩어줘서 마지막 샤드에 몰리는 걸 막아준다. 리샤딩 대비로 mod N 말고 consistent hashing이나 가상 버킷(예: 1024 슬롯) 위에 얹어두면 노드 추가 때 이동량이 1/N 수준으로 준다.
비용: 범위 스캔이 죽는다. '지난 1시간 오퍼 전부' 같은 쿼리가 모든 샤드로 scatter-gather 되고, 제일 느린 샤드가 전체 p99를 정한다. 정렬·페이지네이션도 샤드별 결과를 앱에서 머지해야 해서 코드가 지저분해진다.
언제: 쿼리 대부분이 연속 구간 조회일 때 — 시계열 대시보드, '이 기간 이벤트 전부', 공장 센서 로그처럼 시간 범위로 읽는 워크로드. 키 순서가 보존되니 한두 샤드만 읽으면 끝난다. HBase/Spanner처럼 자동 split 해주는 스토리지면 운영 부담이 줄어든다.
비용: 키가 시간순이면 모든 쓰기가 마지막 샤드 하나에 몰린다(hot shard) — 샤드를 10대로 늘려도 쓰기 처리량은 1대 그대로다. 키 앞에 salt/버킷을 붙여 우회하면 이번엔 범위 조회가 salt 수만큼 fan-out 된다. split/merge 정책이라는 운영 대상도 하나 늘어난다.
기본은 해시 샤딩이고, 처음부터 consistent hashing(가상 버킷) 위에 얹는다. 점 조회 위주 OLTP면 그걸로 끝이다. 실측으로 쿼리의 70% 이상이 연속 범위 스캔이고 그 scatter-gather가 p99를 무너뜨리는 게 확인되면, 그 액세스 패턴만 시간 버킷+해시 조합이나 range 샤딩으로 옮긴다. 특정 키 하나가 뜨거운 건(인기 매물, 대형 거래처) 샤딩 방식을 바꿀 일이 아니라 그 키만 캐시·복제·salt로 따로 푼다.
- 샤드 간 쓰기 QPS 편차가 평균의 2배 이상, 또는 한 샤드가 전체 쓰기의 30% 이상 — 핫 샤드가 생겼다는 신호
- 범위 조회가 전 샤드 scatter-gather로 나가며 p99가 500ms를 넘고, 단일 샤드 점 조회보다 5배 이상 느림 — 액세스 패턴과 샤드 키가 어긋났다는 뜻
- 키 하나(인기 매물·대형 고객)가 자기 샤드 트래픽의 20% 이상을 차지 — 샤딩 방식이 아니라 그 키만 캐시/복제/salt로 풀 문제
- 노드 한 대 추가에 전체 키의 절반이 이동하고 마이그레이션 큐 깊이가 줄지 않고 계속 증가 — mod N으로 시작했다는 뜻, consistent hashing으로 갈아탈 때
🔧Vitess / Citus (hash & range sharding)DynamoDB (partition key + write sharding/salt)Redis Cluster (16384 hash slots)Cassandra (consistent hashing ring)Grafana per-shard QPS / skew 대시보드
“I default to hash sharding for even spread; I'd only go range-based when contiguous scans dominate the workload.”
checking microphone…