이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Hot partition은 평균 부하와 어떻게 다르게 관측해야 하는가?
  • Rebalancing은 데이터 이동 외에 어떤 routing, 검증, rollback 절차를 요구하는가?
  • Hot key 완화는 성능, 정합성, 장애 격리, 운영 복잡도 중 무엇을 바꾸는가?

개요

Hot partition은 전체 시스템 평균은 괜찮아 보이는데 특정 shard, partition, key만 과열되는 상태다. Sharding을 해도 특정 key에 트래픽이 몰리면 한 shard만 병목이 된다. 유명 판매자, 대형 tenant, 이벤트 상품, 인기 게시글, 특정 시간대 batch가 대표 원인이다. Rebalancing은 데이터를 다시 배치해 부하를 낮추는 작업이다. 하지만 데이터 이동은 단순 복사가 아니다. Routing 변경, dual read/write, backfill, 검증, cutover, rollback이 함께 필요하다.

이 문서가 바꾸는 설계 축

바뀌는 내용
성능특정 shard나 key에 몰린 read/write 부하를 분산한다.
정합성이동 중 old/new 위치의 데이터 불일치와 중복 write를 다뤄야 한다.
장애 격리hot key가 전체 shard를 망가뜨리지 않게 격리할 수 있다.
운영 복잡도routing version, migration worker, 검증, rollback runbook이 필요해진다.

평균이 숨기는 문제

다음 지표만 보면 시스템은 아직 버틸 수 있어 보인다.

전체 DB CPU 평균 = 58%
전체 read QPS = 20,000
전체 write TPS = 1,200
p95 latency = 180ms

하지만 shard별로 보면 다를 수 있다.

shardCPUwrite TPSp95 latencylock wait
shard-042%210120ms낮음
shard-189%690950ms높음
shard-248%180130ms낮음
shard-351%120140ms낮음
평균 지표는 shard-1 장애를 숨긴다.
Hot partition을 찾으려면 per-shard, per-partition, per-key 지표가 필요하다.

대표 시나리오

Marketplace에서 유명 판매자 하나가 라이브 판매를 시작했다고 하자. 주문 write의 35%가 seller_id = 91로 몰린다. Shard key가 seller_id라면 이 판매자의 주문은 모두 같은 shard로 간다. Hash를 쓰더라도 같은 key 자체가 뜨거우면 분산되지 않는다. 이때 app scale out은 주문 요청을 더 많이 받아 hot shard로 더 빨리 밀어 넣을 수 있다. 먼저 유입 제한, queue buffering, hot seller 격리, key split을 함께 검토한다.

탐지 지표

지표보는 이유위험 신호
qps_by_shardshard별 부하 편차한 shard가 평균의 2배 이상
p95_by_shard사용자 영향 분리특정 shard만 latency 급등
lock_wait_by_keyhot row/hot key 탐지특정 key lock wait 증가
top_n_keys상위 key 집중도top 1 key가 전체 20% 이상
queue_lag_by_partitionconsumer partition 편차한 partition만 lag 증가
storage_growth_by_shard장기 skew 확인특정 shard만 빠르게 증가
Dashboard는 평균보다 편차를 먼저 보여줘야 한다.
Alert도 전체 p95 하나가 아니라 shard별 포화와 skew 비율을 포함한다.

완화 선택지

선택효과비용
rate limithot key 유입을 즉시 낮춘다.일부 사용자 요청을 제한한다.
queue bufferingwrite spike를 흡수한다.반영 지연과 중복 처리 설계가 필요하다.
read cache반복 read를 낮춘다.stale data와 invalidation 비용이 생긴다.
hot key split한 key 부하를 여러 bucket으로 나눈다.query merge와 정합성 비용이 생긴다.
tenant isolation대형 tenant를 별도 shard로 분리한다.운영 단위와 비용이 늘어난다.
rebalancing장기 부하 분포를 바로잡는다.migration과 rollback 위험이 크다.
장애 중에는 rebalancing보다 유입 제한과 degradation이 먼저일 때가 많다.
데이터 이동은 느리고 위험하기 때문이다.

Hot key split

특정 판매자 주문이 너무 뜨거우면 key를 한 번 더 나눌 수 있다.

routing_key = seller_id + ":" + bucket(order_id)
bucket_count_for_seller_91 = 16

이 방식은 write 분산에는 효과가 있다. 하지만 판매자별 주문 목록은 16개 bucket을 읽어 merge해야 한다. 정산도 bucket별 결과를 합쳐야 한다. 성능을 얻는 대신 query와 정합성 비용을 낸다. Hot key split은 핵심 write 경로를 살리는 대신 read model이나 집계 pipeline을 요구할 수 있다.

Routing table 방식

Shard 수가 바뀔 수 있다면 단순 modulo보다 routing table이 운영에 유리하다.

routingVersion: 42
buckets:
  0001: shard-a
  0002: shard-a
  0003: shard-b
  0004: shard-c
hotKeys:
  seller:91:
    buckets: 16
    target: dedicated-seller-91

Application은 routing version을 metric과 log에 남긴다. 장애 때 어떤 version으로 요청이 흘렀는지 추적해야 한다. Routing table 변경은 code deploy와 분리하는 편이 안전하다. 단, table 자체가 장애 지점이 되지 않도록 cache, 검증, rollback 경로를 둔다.

Rebalancing 절차

Rebalancing은 다음 순서로 쪼개야 한다.

  1. 이동 대상 key나 bucket을 고른다.
  2. 이동 전 write freeze가 필요한지 판단한다.
  3. 새 shard에 schema와 index를 준비한다.
  4. backfill worker로 과거 데이터를 복사한다.
  5. old/new row count, checksum, sample query를 비교한다.
  6. dual write 또는 change capture로 변경분을 따라잡는다.
  7. routing version을 일부 traffic에만 적용한다.
  8. error rate, latency, mismatch를 보고 cutover한다.
  9. rollback 기준 시간이 지나면 old data 정리를 시작한다. 이 절차가 없으면 “데이터를 옮긴다”는 말은 운영 계획이 아니다.

검증 기준

검증설명
row countold/new 건수가 일치하는지 본다.
checksum주요 column hash가 일치하는지 본다.
business query사용자 API 결과가 같은지 sample로 확인한다.
write gapmigration 중 발생한 변경분이 빠지지 않았는지 본다.
latency새 shard가 목표 p95를 만족하는지 본다.
rollback testrouting version을 되돌릴 수 있는지 확인한다.
검증은 migration 끝에 한 번 하는 행사가 아니다.
Backfill 중, cutover 전, cutover 후 모두 필요하다.

장애 중 판단

Hot partition 장애가 진행 중이면 먼저 피해를 줄인다.

상황우선 조치
특정 key write 폭주key별 rate limit 또는 queue 전환
shard CPU 포화read degrade, cache TTL 연장, heavy query 차단
lock wait 증가transaction 단축, hot row update 분리
consumer partition laghot partition 분리 또는 worker 제한 조정
rebalancing 중 mismatchcutover 중단, routing rollback
장애 중 rebalancing은 마지막 선택에 가깝다.
대부분은 유입을 줄이고, write를 완충하고, 사용자에게 지연 상태를 보여주는 쪽이 먼저다.

개인 프로젝트 기준

  • 평균 QPS가 아니라 shard별 QPS와 top key 비율을 가정값으로라도 보여준다.
  • hot key가 생기는 도메인 상황을 하나 정한다.
  • modulo routing의 한계와 routing table이 필요한 이유를 설명한다.
  • rebalancing을 구현하지 않더라도 backfill, 검증, cutover 순서를 문서에 남긴다.
  • 장애 중에는 “서버 추가”보다 유입 제한과 지연 안내를 먼저 말할 수 있어야 한다.

기업 운영 기준

  • shard별 metric과 top key 분석은 기본 dashboard에 둔다.
  • routing 변경은 승인, versioning, canary, rollback 절차를 가진다.
  • migration worker는 rate limit과 pause/resume 기능을 가져야 한다.
  • 데이터 검증 결과는 audit log로 남긴다.
  • hot tenant나 hot seller는 별도 격리 정책과 비용 모델을 가진다.
  • rebalancing은 정기 훈련과 postmortem 항목으로 다룬다.

위험 신호

  • 전체 평균 CPU만 보고 shard별 편차를 보지 않는다.
  • hash sharding이면 hot key가 사라진다고 말한다.
  • routing table 변경을 code deploy에 묶어 rollback을 어렵게 만든다.
  • backfill은 있는데 변경분 동기화 계획이 없다.
  • row count만 보고 business query 검증을 하지 않는다.
  • 장애 중 데이터 이동으로 즉시 해결하려고 한다.

확인 질문

확인 질문

  • 확인 질문: Hot partition은 왜 평균 지표로 발견하기 어려운가?
    • 답변: 전체 평균은 낮아도 특정 shard, partition, key만 CPU, lock wait, latency가 급등할 수 있기 때문이다.
  • 확인 질문: Rebalancing에서 데이터 복사 다음에 반드시 필요한 것은 무엇인가?
    • 답변: 변경분 동기화, routing version 전환, row count/checksum/business query 검증, rollback 기준이다.
  • 확인 질문: Hot key split의 trade-off는 무엇인가?
    • 답변: write 부하는 분산하지만 read merge, 집계, 정합성, 운영 복잡도가 늘어난다.